java垃圾回收机制
2016-11-26 23:00
246 查看
深入理解java虚拟机是一本非常经典的书籍,每次阅读总能看到新的东西。当然最重要的是实践。在平时个工作过程中,我们很少有机会去调jvm启动参数所以可能对java垃圾回收的实践还是缺乏不少。理论很明白,没有实践操作还是不行的,等到线上有问题不可能直接跑到线上调试。所以平时自己写一些拿来调试分析的案例还是有必要。
以下是书中的几段例子。
1.java虚拟机垃圾回收使用的不是引用计数算法,故可以正确回收互相引用的对象
打印输出:
从结果可以看出可以正常回收对象。
2.内存分配和垃圾回收策略
打印输出:
年轻代大小eden为8M,allocation4在分配时survivor只有1M,Eden已经占用6M,所以此时只能分配到老年代。
3.长期存活的对象进入老年代
MaxTenuringThreshold设置为1
打印输出:
MaxTenuringThreshold参数是设置survivor中对象晋升老年代的阀值。从结果可以看出age超过1后会被分配到老年代。
MaxTenuringThreshold设置为15
打印输出:
在测试这个例子时,开始没有添加System.gc();这句代码一直不能测试出结果,每次对象一开始都会分配到老年代。后来怀疑是jvm启动的时候相同年龄的对象比较多,而这些对象总大小之和超过了survivor区大小的一半,会强制移到老年代,而不去比较MaxTenuringThreshold阀值。所以加上System.gc();进行一下full gc之后再创建对象进行测试。
以下是书中的几段例子。
1.java虚拟机垃圾回收使用的不是引用计数算法,故可以正确回收互相引用的对象
package com.jvm.garbage; import org.junit.Test; /** * 互相引用的对象也会被垃圾回收器回收 -XX:+UseSerialGC -XX:+PrintGCDetails * * @author lcq * */ public class ReferenceCountGC { public Object instance = null; private static final int _1MB = 1024 * 1024; private byte[] bigSize = new byte[2 * _1MB]; @Test public void testGC() { ReferenceCountGC objA = new ReferenceCountGC(); ReferenceCountGC objB = new ReferenceCountGC(); objA.instance = objB; objB.instance = objA; objA = null; objB = null; System.gc(); } }
打印输出:
[GC [DefNew: 2717K->410K(4928K), 0.0024818 secs] 2717K->410K(15872K), 0.0025018 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC [DefNew: 4591K->0K(4928K), 0.0026068 secs] 4591K->4505K(15872K), 0.0026366 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System) [Tenured: 4505K->2457K(10944K), 0.0092492 secs] 6553K->2457K(15872K), [Perm : 1496K->1496K(12288K)], 0.0092814 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] Heap def new generation total 4992K, used 102K [0x241b0000, 0x24710000, 0x29700000) eden space 4480K, 2% used [0x241b0000, 0x241c9a40, 0x24610000) from space 512K, 0% used [0x24610000, 0x24610000, 0x24690000) to space 512K, 0% used [0x24690000, 0x24690000, 0x24710000) tenured generation total 10944K, used 2457K [0x29700000, 0x2a1b0000, 0x341b0000) the space 10944K, 22% used [0x29700000, 0x299664d0, 0x29966600, 0x2a1b0000) compacting perm gen total 12288K, used 1499K [0x341b0000, 0x34db0000, 0x381b0000) the space 12288K, 12% used [0x341b0000, 0x34326f10, 0x34327000, 0x34db0000) ro space 10240K, 54% used [0x381b0000, 0x3872c510, 0x3872c600, 0x38bb0000) rw space 12288K, 55% used [0x38bb0000, 0x3924fb78, 0x3924fc00, 0x397b0000)
从结果可以看出可以正常回收对象。
2.内存分配和垃圾回收策略
package com.jvm.garbage; import org.junit.Test; /** * 垃圾回收 内存分配情况 -XX:+UseSerialGC -Xms20M -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8 * XX:SurvivorRatio表示eden:survivor=8:1 * * * @author lcq * */ public class TestAllocation { private static final int _1MB = 1024 * 1024; @Test public void testAllocation() { byte[] allocation1, allocation2, allocation3, allocation4; allocation1 = new byte[2 * _1MB]; allocation2 = new byte[2 * _1MB]; allocation3 = new byte[2 * _1MB]; allocation4 = new byte[4 * _1MB]; } }
打印输出:
[GC [DefNew: 6945K->410K(9216K), 0.0042955 secs] 6945K->4506K(19456K), 0.0043188 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] Heap def new generation total 9216K, used 6751K [0x32db0000, 0x337b0000, 0x337b0000) eden space 8192K, 77% used [0x32db0000, 0x333e1300, 0x335b0000) from space 1024K, 40% used [0x336b0000, 0x33716af0, 0x337b0000) to space 1024K, 0% used [0x335b0000, 0x335b0000, 0x336b0000) tenured generation total 10240K, used 4096K [0x337b0000, 0x341b0000, 0x341b0000) the space 10240K, 40% used [0x337b0000, 0x33bb0020, 0x33bb0200, 0x341b0000) compacting perm gen total 12288K, used 1499K [0x341b0000, 0x34db0000, 0x381b0000) the space 12288K, 12% used [0x341b0000, 0x34326e30, 0x34327000, 0x34db0000) ro space 10240K, 54% used [0x381b0000, 0x3872c510, 0x3872c600, 0x38bb0000) rw space 12288K, 55% used [0x38bb0000, 0x3924fb78, 0x3924fc00, 0x397b0000)
年轻代大小eden为8M,allocation4在分配时survivor只有1M,Eden已经占用6M,所以此时只能分配到老年代。
3.长期存活的对象进入老年代
package com.jvm.garbage; import org.junit.Test; /** * 垃圾回收 内存分配情况 -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 * -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution * * @author lcq * */ public class TestTenuringThreshold { private static final int _1MB = 1024 * 1024; @Test public void testTenuringThreshold() { System.gc(); byte[] allocation1, allocation2, allocation3; allocation1 = new byte[_1MB / 4]; allocation2 = new byte[4 * _1MB]; allocation3 = new byte[4 * _1MB]; allocation3 = null; allocation3 = new byte[4 * _1MB]; } }
MaxTenuringThreshold设置为1
打印输出:
[Full GC (System) [Tenured: 0K->410K(10240K), 0.0102130 secs] 2849K->410K(19456K), [Perm : 1495K->1495K(12288K)], 0.0102419 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] [GC [DefNew Desired survivor size 524288 bytes, new threshold 1 (max 1) - age 1: 262160 bytes, 262160 total : 4515K->256K(9216K), 0.0026166 secs] 4926K->4762K(19456K), 0.0026376 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC [DefNew Desired survivor size 524288 bytes, new threshold 1 (max 1) : 4352K->0K(9216K), 0.0002393 secs] 8858K->4762K(19456K), 0.0002552 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap def new generation total 9216K, used 4344K [0x32db0000, 0x337b0000, 0x337b0000) eden space 8192K, 53% used [0x32db0000, 0x331ee330, 0x335b0000) from space 1024K, 0% used [0x335b0000, 0x335b0000, 0x336b0000) to space 1024K, 0% used [0x336b0000, 0x336b0000, 0x337b0000) tenured generation total 10240K, used 4762K [0x337b0000, 0x341b0000, 0x341b0000) the space 10240K, 46% used [0x337b0000, 0x33c56b80, 0x33c56c00, 0x341b0000) compacting perm gen total 12288K, used 1499K [0x341b0000, 0x34db0000, 0x381b0000) the space 12288K, 12% used [0x341b0000, 0x34326e60, 0x34327000, 0x34db0000) ro space 10240K, 54% used [0x381b0000, 0x3872c510, 0x3872c600, 0x38bb0000) rw space 12288K, 55% used [0x38bb0000, 0x3924fb78, 0x3924fc00, 0x397b0000)
MaxTenuringThreshold参数是设置survivor中对象晋升老年代的阀值。从结果可以看出age超过1后会被分配到老年代。
MaxTenuringThreshold设置为15
打印输出:
[Full GC (System) [Tenured: 0K->410K(10240K), 0.0106688 secs] 2849K->410K(19456K), [Perm : 1495K->1495K(12288K)], 0.0106981 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] [GC [DefNew Desired survivor size 524288 bytes, new threshold 15 (max 15) - age 1: 262160 bytes, 262160 total : 4515K->256K(9216K), 0.0026352 secs] 4926K->4762K(19456K), 0.0026572 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [GC [DefNew Desired survivor size 524288 bytes, new threshold 15 (max 15) - age 2: 262160 bytes, 262160 total : 4352K->256K(9216K), 0.0002356 secs] 8858K->4762K(19456K), 0.0002519 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] Heap def new generation total 9216K, used 4600K [0x32db0000, 0x337b0000, 0x337b0000) eden space 8192K, 53% used [0x32db0000, 0x331ee330, 0x335b0000) from space 1024K, 25% used [0x335b0000, 0x335f0010, 0x336b0000) to space 1024K, 0% used [0x336b0000, 0x336b0000, 0x337b0000) tenured generation total 10240K, used 4506K [0x337b0000, 0x341b0000, 0x341b0000) the space 10240K, 44% used [0x337b0000, 0x33c16b70, 0x33c16c00, 0x341b0000) compacting perm gen total 12288K, used 1499K [0x341b0000, 0x34db0000, 0x381b0000) the space 12288K, 12% used [0x341b0000, 0x34326e60, 0x34327000, 0x34db0000) ro space 10240K, 54% used [0x381b0000, 0x3872c510, 0x3872c600, 0x38bb0000) rw space 12288K, 55% used [0x38bb0000, 0x3924fb78, 0x3924fc00, 0x397b0000)晋升阀值设置为15后,对象会保持在survivor区中。
在测试这个例子时,开始没有添加System.gc();这句代码一直不能测试出结果,每次对象一开始都会分配到老年代。后来怀疑是jvm启动的时候相同年龄的对象比较多,而这些对象总大小之和超过了survivor区大小的一半,会强制移到老年代,而不去比较MaxTenuringThreshold阀值。所以加上System.gc();进行一下full gc之后再创建对象进行测试。
相关文章推荐
- Java的垃圾回收机制详解和调优
- Java的垃圾回收(Garbage Collection)机制
- JVM详解之Java垃圾回收机制详解和调优
- 【转载】 全面分析Java的垃圾回收机制
- 深刻剖析经典面试题之二:Java与C#的垃圾回收机制
- Java与C#的垃圾回收机制
- Java的垃圾回收机制
- java的垃圾回收机制详解和调优
- Java与C#的垃圾回收机制
- java中的垃圾回收机制
- Java垃圾回收机制浅解
- 全面分析Java的垃圾回收机制
- java中的垃圾回收机制GC
- Java垃圾回收机制详解和调优
- Java的垃圾回收机制详解和调优
- JAVA垃圾回收机制与内存泄露问题
- Java的垃圾回收机制详解和调优大全
- 深刻剖析经典面试题之二:Java与C#的垃圾回收机制
- 全面分析Java的垃圾回收机制
- JVM详解之Java垃圾回收机制详解和调