您的位置:首页 > 编程语言 > Java开发

java垃圾回收机制

2016-11-26 23:00 246 查看
深入理解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 [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之后再创建对象进行测试。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: