JVM(二):垃圾回收
三个问题:
那些内存需要回收? -- 对象是否存活判断
什么时候回收? --垃圾回收触发条件
如何回收? --垃圾回收算法
垃圾回收应用 -- 理解GC日志、使用垃圾回收命令和工具
1. 判断对象是否存活
- 引用计数法
- 可达性分析算法
引用计数法:给对象增添一个计数器,每当被引用一次,计数器数值+1;引用失效则-1;当计数器为0时,该对象不再被使用。
优点:实现简单,判定效率高。
缺点:不能解决对象之间相互循环引用问题。
VM参数配置 -Xms100m -Xmx100m -XX:+PrintGCDetails(打印GC日志)
public class LeetCode { public Object instance = null; public static void main(String[] args){ testGC(); } public static void testGC(){ LeetCode leetCode1 = new LeetCode(); LeetCode leetCode2 = new LeetCode(); leetCode1.instance = leetCode2; leetCode2.instance = leetCode1; leetCode1 = null; leetCode2 = null; System.gc(); } }
GC日志:
这两个互相引用的对象被回收了,说明采用的不是引用计数法
可达性分析算法:
GCRoots:
- 虚拟机栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(即一般说的Native方法)引用的对象
判断对象的引用链是否能够到达GC Roots,能到达则为存活,不能则是已经死亡
2. 回收步骤、
2.1 是否可达
2.2 标记,然后筛选 是否有必要执行finalize()方法
2.3 有必要的话,放置到F-Queue队列,由虚拟机自动建立一个低优先级的Finalizer线程去执行每个对象的finalize();
2.4 GC回对F-queue的对象进行二次标记,finalize是对象逃脱死亡的最后一次机会。
3.回收算法
3.1 标记-清除算法
3.2 复制算法-被商业虚拟机广泛采用收集新生代的算法
将内存分为两块,每次只用其中一块,当这块内存用完了,将仍然存活的对象复制到另外一块上面,然后把已使用的内存空间一次清理。
实现简单,运行高效,但是会浪费一部分内存空间
记住一个比例 8:1:1 Eden:From Survivor: To Survivor
3.3 标记整理算法
3.4 分代收集算法 (新生代:复制算法 老年代:标记-清理算法)
并没有创新的算法,而是在合适的区域采用合适的回收算法。