今天看到一篇关于JVM-GC的帖子,写了一段jvm参数设置对内存垃圾回收的影响,写的是挺精彩的,其中有一部分,没有写具体的分析过程,我觉得还是挺有必要的,特别是对刚刚入门jvm的tx,本文的原材料来自https://blog.csdn.net/qq_30739519/article/details/51055487
废话不多说,上原材料:
代码块
byte[] b = null;
for (int i = 0; i < 10; i++) {
b = new byte[1 * 1024 * 1024];
}
jvm启动参数设置
-Xmx20m -Xms20m -XX:NewRatio=2 -XX:+PrintGCDetails
GC日志打印
[GC [DefNew: 4899K->474K(6144K), 0.0016090 secs] 4899K->1498K(19840K), 0.0016426 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC [DefNew: 5768K->0K(6144K), 0.0011308 secs] 6792K->2522K(19840K), 0.0011490 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 6144K, used 1134K [0x335d0000, 0x33c70000, 0x33c70000)
eden space 5504K, 20% used [0x335d0000, 0x336eb8c8, 0x33b30000)
from space 640K, 0% used [0x33b30000, 0x33b30088, 0x33bd0000)
to space 640K, 0% used [0x33bd0000, 0x33bd0000, 0x33c70000)
tenured generation total 13696K, used 2522K [0x33c70000, 0x349d0000, 0x349d0000)
the space 13696K, 18% used [0x33c70000, 0x33ee6878, 0x33ee6a00, 0x349d0000)
compacting perm gen total 12288K, used 146K [0x349d0000, 0x355d0000, 0x389d0000)
the space 12288K, 1% used [0x349d0000, 0x349f4a58, 0x349f4c00, 0x355d0000)
ro space 10240K, 45% used [0x389d0000, 0x38e59b28, 0x38e59c00, 0x393d0000)
rw space 12288K, 54% used [0x393d0000, 0x39a5d0e8, 0x39a5d200, 0x39fd0000)
GC分析:
- jvm内存堆总大小为20M,老年代和新生代比例我们设置的是2:1,所以新生代的内存大约是6144K,老年代的内存是13696K
- 由于from/to区域都无法容纳一个1M的空间,所以最终的结果是两个1M的空间跑到老生带去了,一个1k的空间停留在eden区中
- 重点来了,为何有两个1M的内存跑到老生待去了,不应该全部被GC掉了嘛?
原因是在分配第5个1M的空间的时候,进行GC,只能回收前面3个,第四个1M的空间被变量b引用着,这时候这个不能被回收掉,from和to区域也放不下,只能放到年老代,第二个1M也是这么进入的年老代,由于没有发生年老代的fullGC,所以这块内存一直存活到程序结束。这就能解释为啥最后2个1M在年老代,一块1M在年轻代。