JVM gc基本算法简介

看了一些网上的资料,也写一篇关于jvm的gc算法。

一.引用计数(reference counnting)

   对于java虚拟机中创建的每一个对象。添加一个引用计数值。当赋值函数将该对象赋给一个引用时,该对象的引用计数值加一。当某个引用的生命周期到时,引用计数值减一。当引用计数值为0时,可以GC则将该对象销毁。


二.标记-清除收集器(Mark-Swap Collector)
  垃圾清理的过程分为两个阶段
   1. 首先停止所有的工作,从根集遍历所有的被引用的节点,并做上标记。然后恢复所有的工作
   2.收集阶段会收集那些没有被标记的节点,然后返回空闲链表。


  标记-清除算法的缺点,
1.标记阶段的暂停的时间太长,而整个堆在暂停阶段又是可以被访问的,故可能被换出内存。
2.另一个问题,无论对象是否可达,是否是垃圾,在标记阶段都要进行标记,耗费大量的时间。
3.标记清除这两个动作会产生大量的内存碎片。当有大的对象创建时,则需要进行内存清理。

三.拷贝收集器(Copying Collectors)(适用于young generation)

  将内存分为两个区域(from space 和 to space),所有的对象分配内存都分配到from space区域。在清理对象时,将所有标志为活动的对象copy 到to space中,清空from space。然后互换to space 和from space。每次清理,重复上述的过程。

一般都使用该算法来回收新生代的对象,因为大多数的新生代的生命周期都很短,所以两块相互切换的区域并不需要1比1来分配。一般是分配一个Eden区和两个Survivor区域。大部分的对象都是在Eden区域生成,当垃圾回收时,Eden和其中的一个Survivor区中存货的对象复制到另一个Survivor区域中,经过几次复制以后还存活的对象将被升格为tenured对象,复制到其他的区域中。
Survivor两个区域是对称的,没有先后的关系。Survivor总有一个是空的。
young generation的GC称为minor gc。经过数次minor gc依然存活的对象,将被移到tenured generation。

优点:copy算法不理会非活动的对象,copy 数量取决于活动的对象的数量。在copy同时,整理了heap空间。to space空间始终是连续的,内存使用效率得到了提高。
缺点:一般情况Eden:Survivor=8:1故总有10%的新生代内存会被浪费掉。

四.标记-整理收集器(Mark-Compact Collector)(适用于存放周期较长的tenured generation的对象)
标记整理收集器,通过融合了标记-清除收集器和copy收集器的优点,很好的解决了copy收集器中的内存浪费的问题。
标记整理搜集器分为两个阶段:
1.标记阶段,这个和标记-清除收集器的标记阶段相同
2.整理阶段,这个阶段将做了标记的活动对象整理到堆得底部(类似于磁盘清理)
存入到tenured generation的对象,一般都经过多次的minor gc,还活着的对象,将会被移到tenured中。(minor gc 过程中某一个Survivor 区域装满时,会被直接装路到tenured generation中)tenured gc 被称为marjor gc,就是通常的full gc。tenured generation  区域较大,则该对象的生命周期都较长。故major gc 的时间也长。

minor gc  可能会引发full  gc 。当Eden + from space  的空间大于tenured generation区域的剩余空间时,会引发full gc。这是悲观算法。要确保Eden + from space区域都存活,所以必须有足够的tenured generation区域来存储。

如果使用分代算法的话,还有一个永久带Permanent generation 区域。该区域主要用于存放classloader信息。比如method信息。
spring hibernate 对于这些需要动态类型支持的框架,这个区域要足够的空间。(这部分的空间存在于方法区,不在堆中)。

你可能感兴趣的:(java,jvm)