java垃圾回收机制

来源:互联网 发布:淘宝运营培训班 编辑:程序博客网 时间:2024/06/17 12:25

深入理解java虚拟机是一本非常经典的书籍,每次阅读总能看到新的东西。当然最重要的是实践。在平时个工作过程中,我们很少有机会去调jvm启动参数所以可能对java垃圾回收的实践还是缺乏不少。理论很明白,没有实践操作还是不行的,等到线上有问题不可能直接跑到线上调试。所以平时自己写一些拿来调试分析的案例还是有必要。


以下是书中的几段例子。


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 [DefNewDesired 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 [DefNewDesired 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 [DefNewDesired 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 [DefNewDesired 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之后再创建对象进行测试。




0 0
原创粉丝点击