JVM-GC算法

程序计数器、虚拟机栈、本地方法栈3个区域随线程而生随线程而灭,内存分配和回收都具有确定性,因此不需要过多考虑回收的问题。java堆和方法区则不一样,内存的分配和回收是动态的,垃圾收集器所关注的也是这部分内存。

判断对象已经死去的算法

一、引用计数算法:

    给对象添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻计数器为0的对象就是不可能再被使用的。

但是主流的Java虚拟机里面并没有选用引用计数算法来管理内存,主要原因是它很难解决对象之间相互循环引用的问题

二、可达性分析算法:

    通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时(相当于一棵树,到这个节点不可达时),则证明此对象是不可用的。

就算根据算法判断出了对象已经没有引用了,也不是立马回收,它还有机会。需要经过两次标记,第一次标记是发现没有引用链之后,第二次标记是从已经被标记的对象中筛选出一部分,条件是对象有必要执行finalize()方法(被重写和没有被调用过)。在第二次标记后执行finalize()方法有机会逃脱死亡命运,只要重新与引用链上的任何一个对象建立关系即可,比如在finalize()方法中把自己(this关键字)赋值给某个类变量或对象的成员变量。

垃圾收集算法:

一、标记-清除算法

    首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。后续算法都是基于这种思路并对其不足进行改进。它的不足主要是效率不高和空间问题(会产生大量不连续的内存碎片)。

二、复制算法(新生代)

    将可用内存按容量划分成大小相等的两块,每次只使用其中的一块。当这块的内存用完了,就将还存活的对象复制到另一块上面,然后再把已使用过的内存空间一次清理掉。代价就是内存缩小为原来的一半。现在商业虚拟机用这种收集算法来回收新生代。98%的对象是朝生夕死的,所以不需要1:1分配。而是按8:1:1分配,每次使用一块大的和一块小的内存,每次回收时,将存活的对象放入另一块小的内存中。但是不是每次存活的都是少量的对象,如果那一小块对象不够用时,可以采用分配担保机制,将这些对象直接通过分配担保机制进入老年代。

三、标记-整理算法(老年代)

    复制收集算法在对象存活率较高时就要进行较多的复制操作,效率降低,而且还需要有额外的空间进行分配担保。所以老年代中一般不选用这种算法。

标记-整理算法的标记过程与标记-清除算法一样, 但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

四、分代收集算法

    当前商业虚拟机的垃圾收集都采用“分代收集”算法,根据对象存活周期的不同将内存划分为几块。一般是把java堆分为新生代和老年代。根据各个年代的特点采用最适当的收集算法。


猜你喜欢

转载自blog.csdn.net/dear_mango/article/details/80712760