Java虚拟机——GC算法

学习Java总是避不开jvm的,毕竟整个java都运行在这个虚拟机上,可能以后会把虚拟机独立出来成为一个分类罢。

GC算法介绍

Garbage Collection,垃圾收集,即内存回收,我们都知道Java是不需要程序员手动管理内存的,因为java有一个垃圾清理器的东西存在,Java中,GC的对象是Java堆和方法区(即永久区)。垃圾指的是在系统运行过程当中所产生的一些无用的对象,这些对象占据着一定的内存空间,如果长期不被释放,可能导致OOM。

GC算法分类

   

引用计数法(无法解决循环引用的问题,不被java采纳)

对每一个对象,都有一个计数器,当别的地方有对象引用他的时候,该计数器+1,垃圾清理会清理掉计数器为0的对象,但是当两个对象循环引用时,该算法就失效了。

根搜索算法

由于引用计数算法的缺陷,所以JVM一般会采用一种新的算法,叫做根搜索算法。它的处理方式就是,设立若干种根对象,当任何一个根对象到某一个对象均不可达时,则认为这个对象是可以被回收的。

现代虚拟机中的垃圾搜集算法:

现代虚拟机中的垃圾收集算法都是对根搜索算法的一种扩充。

标记-清除

标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象;然后,在清除阶段,清除所有未被标记的对象。

但是这个算法的问题就是效率地下,同时会空出大量零碎的内存空间,利用率非常低。

复制算法(新生代)

将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收。

这种算法很适合对象周期短的程序,问题在于对空间的浪费非常严重

标记-压缩(老年代)

和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记;但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端;之后,清理边界外所有的空间。

这种算法适合长周期的对象,减少了对象的复制,不仅可以弥补标记/清除算法当中,内存区域分散的缺点,也消除了复制算法当中,内存减半的高额代价。

但是,标记/整理算法唯一的缺点就是效率也不高。

不仅要标记所有存活对象,还要整理所有存活对象的引用地址。从效率上来说,标记/整理算法要低于复制算法。

分代收集

当前商业虚拟机的GC都是采用的“分代收集算法”,这并不是什么新的思想,只是根据对象的存活周期的不同将内存划分为几块儿。一般是把Java堆分为新生代和老年代:短命对象归为新生代,长命对象归为老年代。

少量对象存活,适合复制算法:在新生代中,每次GC时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成GC。

大量对象存活,适合用标记-清理/标记-整理:在老年代中,因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-清理”/“标记-整理”算法进行GC。

总结

可以说时间与空间不能兼得,对方法的组合可以同时利用两方面的优势。

发表评论

电子邮件地址不会被公开。 必填项已用*标注