最近时间比较紧张,要写的东西也有很多,只能想到一点写一点。关于GC,网上的资料太多,之前对一个系统调优的时候又回顾了一下,找了几篇广泛流传的资料,大部分都是大同小异,这里总个总结,希望能够做个相对的全集,并写出一些新的点,比如Card Marking(卡片标记)等。
首先是大家都要提到的GC的基础算法:标记清除,标记整理,复制,分代。这些算法的第一步都是做的一件事: 标记(Mark)。
JVM的标记算法采用了根搜索算法(Root Tracing)。根有几种:
1. JVM栈的Frame里面的引用
2. 静态类,常量的引用
3. 本地栈中的引用
4. 本地方法的引用
一般我们能控制的就是JVM栈中的引用和静态类,常量的引用。标记也分为几个阶段,比如
1. 标记直接和根引用的对象
2. 标记间接和根引用的对象
3. 由于分代算法,被老年代对象所引用的新生代的对象
对于第三种,JVM采用了Card Marking(卡片标记)的方法,避免了在做Minor GC时需要对整个老年代扫描。具体的方法如下:
1. 将老年代的内存分片,1个片默认是512byte
2. 如果老年代的对象发生了修改,就把这个老年代对象所在的片标记为脏 dirty。或者老年代对象指向了新生代对象,那么它所在的片也会被标记为dirty
3. 没有标记为脏的老年代片它没有指向新的新生代对象,所以可以不需要去扫描
4. Minor GC扫描老年代空间时,只需要去扫描脏的卡片的对象,不需要扫描整个老年代空间
所以做Minor GC时标记的时间 = T(stack_scan) + T(card_