程序员技术干货

JVM垃圾回收策略

2018-11-18  本文已影响133人  匠丶

本文将分析JVM的垃圾回收策略,哪些内存需要回收和如何回收的问题。

哪些内存需要回收

垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还存活着,哪些已经死去。

引用计数算法

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

引用计数算法的缺陷是不能解决对象之间互相引用的问题,因此不被主流虚拟机选用。

可达性分析算法

通过一系列的称为GC Roots的对象作为起始点,从这些节点开始向下搜索,搜索所经过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,这个对象就是不可用的。


在java语言中,可作为GC Roots的对象包括:
引用的分类

java的引用可以分为强引用、软引用、弱引用、虚引用:

垃圾收集算法

标记-清除算法

最基础的收集算法是“标记-清除”(Mark-Sweep)算法,如同它的名字一样,算法分为标记和清除两个阶段。
标记:首先标记所有需要回收的对象
清除:在标记完成后统一回收所有被标记的对象


缺点:
复制算法(新生代算法)

它将可用内存按容量划分为大小相等的两块,每次只用其中的一块。当这一块内存用完之后,将还存活的对象复制到另一块去,然后再把已使用过的内存空间一次清理掉。

优点:每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。

缺点:代价是将内存缩小为了原来的一半,未免太高了一点。

现在的商用虚拟机都采用这种手机算法来回收新生代,IBM公司的专门研究表明,新生代中的对象98%是“朝生夕死”,所以并不需要按照1:1的比例来划分内存空间。

解决方法:将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性复制到另外一块Survivor空间上,最后清理掉Eden和刚才用过的Survivor空间。

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

复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。所以在老年代一般不能直接选用这种算法。根据老年代的特点,提出了“标记-整理”(Mark-Compact)算法。标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。


分代收集算法

当前商用虚拟机都采用了这种算法,根据对象的存活周期将内存划分为几块,一般是把Java堆分为新生代和老生代,根据各个年代采用适当的收集算法。

上一篇 下一篇

猜你喜欢

热点阅读