深入理解JVM:GC机制

垃圾回收机制用来自动回收内存,其概念不用在详解。

问题

首先说明,目前商业虚拟机采用的均为:分代收集算法。所以先引出第一个概念:什么是分代?其产生的根源是什么?

内存模型

虚拟机将其所占用的内存按照虚拟机所设计的逻辑,根据存放的东西不同而划分。
深入理解JVM:GC机制

一般在程序中,new出来的对象保存在“堆”上。我们这里讲的就是作用在“堆”上的GC。
要明白一个前提,所有算法的进步都是一个过程,都有一个最开始、最简单的模型。

GC算法

由易到复杂的GC算法:
1. 标记-清除
在内存块中先标记需要被回收的块,然后再回收。至于如何被回收,是另一部分的知识了。整理结果造成内存物理上的不连续。
2. 标记-整理
也是先标记要被回收的内存块,然后清除,然后整理成一个物理上连续的大块。
3. 复制。
这种是将内存分为左右两块(形象的表述),左边使用的同时,右边不使用。当左边GC时,把标记要回收的块回收掉,剩下的就是不用回收和没有用到的内存卡。然后复制到右边。这样,左边是空的未使用的内存,右边是连续的了。下次gc再换过来。
4. 高级复制算法
上边的复制算法将内存一分为二,很粗放。为了更精细化的管理内存。。其实是IBM研究人员发现,GC的时候,有98%的对象是可以被回收的。所以后来将内存一分为三:占80%的区域叫Eden,10%的叫Survivor1,10%的叫Survivor2(HotSpot默认比例,1和2是我自己加的,其实都是Survivor)。这次复制就是将Eden和一个Survivor的对象,复制到剩下的那个Survivor里。等同于上边的复制算法,就是划分了一定区域。可以使GC的代价没那么大。如果Survivor撑不下那90%内存里剩下的不用被回收的对象怎么办?可以借用另一块内存:老年代内存。


总结

根据对象存活时间不同,一般将内存划分为新生代和老年代。还有一个永久代,也叫常量池,也叫方法区(其实这么叫不对,但这样理解没事),就是上图内存模型里的在不同内存上,应用不同的GC算法,就是现在商业虚拟机所采用的思想。 新生代用高级复制算法,老年代用标记-清理、标记-整理。

问题思考

如何标记内存该不该被回收?
1. 引用计数
一般商业虚拟机用引用计数的方式,一个对象被引用时,就+1,没有被引用就是0,回收就回收引用为0的。但是当A引用B,B也引用A时,就永远被回收不了。
2. 可达性
利用图论的思想,将引用看作一张可达图。根节点是栈帧,子节点是栈帧里的对象。(什么是栈帧?就是一个class,不同class之间的栈是隔离的。所以一个一个的class就有了一个一个栈帧。。)。如果对象不可达,那就要被标记是否清除。但这个思想不会这么简单就结束。