垃圾收集器与内存分配策略
1. 引用计数GC算法
每个对象都会有对应的计数器来计算对象引用,但JVM不会采用该策略,因为不能解决对象相互引用的回收。
public class ReferenceCountingGC { public Object instance = null; private static final int _1M = 1024 * 1024; private byte[] bigSize = new byte[2 * _1M]; public static void main(String[] args) { // TODO Auto-generated method stub ReferenceCountingGC objA = new ReferenceCountingGC(); ReferenceCountingGC objB = new ReferenceCountingGC(); objA.instance = objB; objB.instance = objA; objA = null; objB = null; //GC System.gc(); } }
设置VM参数,打印GC日志
-XX:+PrintGC
-XX:+PrintGCDetails
部分GC日志:
[GC (System.gc()) [PSYoungGen: 6758K->584K(38400K)] 6758K->592K(125952K), 0.0015223 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 584K->0K(38400K)] [ParOldGen: 8K->515K(87552K)] 592K->515K(125952K), [Metaspace: 2554K->2554K(1056768K)], 0.0048039 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
可以从PSYoungGen中明显看到对象被回收,也就是JVM并没有采用引用计数算法。
2. 可达性分析算法
public class FinalizeEscapeGC { public static FinalizeEscapeGC instance = null; @Override protected void finalize() throws Throwable { // TODO Auto-generated method stub super.finalize(); System.out.println("finalize() executed"); FinalizeEscapeGC.instance = this; } public static void main(String[] args) throws InterruptedException { FinalizeEscapeGC.instance = new FinalizeEscapeGC(); //在finalize()中拯救自己 - 成功 instance = null; System.gc(); //finalize()优先级很低,sleep Thread.sleep(500); if(instance != null) { System.out.println("still alive"); }else { System.out.println("object recycling"); } //再尝试自救 - 失败 instance = null; System.gc(); Thread.sleep(500); if(instance != null) { System.out.println("still alive"); } else { System.out.println("object recycling"); } } }
在第一次GC时,finalize()第一次执行并将this赋予对象instance,因此this未被回收。但覆盖的finalize()仅执行一次,因此第二次GC时,对象被回收。
清醒时做事,糊涂时读书,大怒时睡觉,独处时思考; 做一个幸福的人,读书,旅行,努力工作,关心身体和心情,成为最好的自己
-- 共勉