1.Java源码编译机制
结构信息,元数据,方法信息
Java代码编译

Java字节码的执行

2.类加载机制
classloader及其子类
bc jre.lib.rt.jar
ec jre.lib.ext.*.jar
ac classpath指定jar
cc 自定义c
3.类执行机制
基于堆栈的虚拟机,一个线程一个堆栈。已帧为单位保存线程。jvm以帧为单位进行出入栈。
帧通常用来存放数据和部分结果,通常还有执行动态链接,方法返回值和异常调度。
在方法调用的同一时刻,一个新帧就会随之创建,当方法执行完成的时候(无论这个方法是正常完成还是意外完成),帧都会随之销毁。在线程创建帧的时候,Java虚拟机栈就会分配内存空间给帧。每个帧都有自己的局部变量表、操作数栈、当前方法对应类的运行时常量池的引用。
当只有一个方法正在执行并且只有一个帧的时候,可以根据线程调配随时激活。此时,这个帧称为当前帧,并且这个帧对应的方法称为当前方法,这个方法所在的类称为当前类。对局部变量表和操作数栈的操作通常都会引用当前帧。
如果方法调用其他方法或者方法执行完成时,方法的帧会随之销毁。当方法把控制权转移到新方法的时候,新方法就会执行,在执行的同时生成一个新的帧,新帧会切换成当前帧。对于方法返回,当前帧会返回帧对应方法的执行结果。更有可能,会返回到前一帧。当前一帧变成当前帧的时候,之前的当前帧就会销毁。
==注意:线程创建的帧是线程的私有空间,其他线程均不能引用==
问题1. 如何解决同时存在的对象创建和对象回收问题
答:垃圾回收线程是回收内存的,而程序运行线程则是消耗(或分配)内存的,一个回收内存,一个分配内存,从这点看,两者是矛盾的。因此,在现有的垃圾回收方式中,要进行垃圾回收前,一般都需要暂停整个应用(即:暂停内存的分配),然后进行垃圾回收,回收完成后再继续应用。这种实现方式是最直接,而且最有效的解决二者矛盾的方式。
但是这种方式有一个很明显的弊端,就是当堆空间持续增大时,垃圾回收的时间也将会相应的持续增大,相应应用暂停的时间也会相应的增大。一些相应时间要求很高的应用,比如最大暂停时间要求是几百毫秒,那么当堆空间大于几个G时,就很有可能超过这个限制,在这种情况下,垃圾回收将会成为系统运行的一个瓶颈。为解决这种矛盾,有了并发垃圾回收算法,使用这种算法,垃圾回收线程与程序运行线程同时运行。在这种方式下,解决了暂停的问题,但是因为需要在新生成对象的同时又要回收对象,算法复杂性会大大增加,系统的处理能力也会相应降低,同时,“碎片”问题将会比较难解决,以后研究的重点!!!!!!。
问题2 为什么要分代
答:分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同声明周期的对象可以采取不同的收集方式,以便提高回收效率。
在Java程序运行的过程中,会产生大量的对象,其中有些对象是与业务信息相关,比如Http请求中的Session对象、线程、Socket连接,这类对象跟业务直接挂钩,因此生命周期比较长。但是还有一些对象,主要是程序运行过程中生成的临时变量,这些对象生命周期比较短,比如:String对象,由于其不变类的特性,系统会产生大量的这些对象,有些对象甚至只用一次即可回收。
试想,在不进行对象存活时间区分的情况下,每次垃圾回收都是对整个堆空间进行回收,花费时间相对会长,同时,因为每次回收都需要遍历所有存活对象,但实际上,对于生命周期长的对象而言,这种遍历是没有效果的,因为可能进行了很多次遍历,但是它们依旧存在。因此,分代垃圾回收采用分治的思想,进行代的划分,把不同生命周期的对象放在不同代上,不同代上采用最适合它的垃圾回收方式进行回收。
虚拟机中共划分了三个代:年轻代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。
问题3 如何分代
答:其中持久代主要存放的是java类的类信息,与垃圾收集要收集的java对象关系不大。年轻代和年老代的划分是对垃圾收集影响比较大的。
年轻代:
所有新生成的对象首先都是放在年轻代的。年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象。年轻代分为三个区。一个Eden区,两个Survivor区(一般而言)。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活将被复制到另外一个Survivor区,当这个Survivor区也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制“年老区(Tenured)”。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来的对象和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor区过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。
年老代:
在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。
持久代:
用于存放静态文件,如java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久空间来存放这些运行过程中新增的类。持久代大小通过 -XX:MaxPermSize = <N> 进行设置。
本文详细介绍了Java内存管理的关键机制,包括源码编译过程、类加载机制及执行机制。重点讲解了垃圾回收策略,如分代回收及并发回收,并探讨了年轻代与年老代的区别。
1692

被折叠的 条评论
为什么被折叠?



