JVM垃圾回收算法标记清除和复制算法

标记清除算法

当堆中的有效空间被耗尽时,JVM就会停止整个程序(也被称为stop the world),然后开始两项工作.一是:标记, 而是:清除

标记

遍历所有GC Roots,将所有GC Roots可达的对象都标记为存活对象.

清除

遍历堆中所有的对象把没有标记的对象全部清除.

在程序运行期间,当堆中的可用内存被耗尽时,GC线程就会启动并停止程序,GC线程将存活的对象标记一遍,没有被标记的对象就是垃圾对象,最后这些垃圾对象会被清除掉,然后重新唤醒应用程序.

程序运行时堆中对象的状态(默认为0未标记,1为标记过),假如堆内存的可用空间被消耗完,那么GC线程就会启动,停止掉应用程序,使用根可达性算法进行搜索标记.

图片alt

被标记后的对象状态

图片alt

使用根可达性算法,所有GC Roots可达的对象都被标记为存活对象,此时已经完成了第一阶段的工作.接下来执行清除操作,执行完清除操作,堆中对象的状态.

图片alt

没有标记的对象被清除,被标记的对象会被留下,标志为被置为0,应用程序被唤醒.

标记清除的优点是算法简单,缺点如下:

1.效率低下,需要遍历整个堆.进行GC的时候需要停止应用程序
2.垃圾回收后的内存空间是不连续的,因为垃圾对象的分布很随意,那么清除后的内存会不连续. 为了解决这个问题,JVM不得不维护一个空闲链表,又会导致额外的开销.

复制算法

复制算法使用了两块同等大小的内存空间,每次只用一块,垃圾回收的时候,把存活的对象直接另外一块内存,然后剩余的垃圾对象全部一次性清除.好处是复制存活对象的时候就不用考虑内存碎片.唯一的缺点就是内存利用率只有50%.

图片alt

现在的虚拟机一般都用复制算法回收新生代,IBM的研究发现,新生代中的对象98%都是朝生夕死,所以并不需要1:1分配对象,而是将内存分为一个大的Eden和两块小的Survivor空间,每次只使用Eden和一块Survivor. 当进行垃圾回收时,将存活对象一次性复制到一块Survivor空间,最后清除掉Eden和使用过的Survivor空间. HotSpot虚拟机Eden:Survivor=8:1,也就新生代可用的内存达到90%,只会有10%的浪费.当然98%的对象可被回收只是一般的场景,并没有办法保证每次Survivor都能存放的下存活对象,若Survivor空间不够时,需要依靠老年代进行分配担保.

图片alt

from ,to为Survivor区。

返回笔记列表
入门小站