11–内存分配策略–长期存活的对象将进入老年代
1、测试
1.1、代码
public class Test {
private static final int _1MB = 1024 * 1024;
//参数
//-verbose:gc
//-Xms20M
//-Xmx20M
//-Xmn10M
//-XX:+PrintGCDetails
//-XX:SurvivorRatio=8
//-XX:MaxTenuringThreshold=1 //最大分代年龄为1
//-XX:+PrintTenuringDistribution
//-XX:+UseSerialGC
public static void main(String[] args) {
byte[] allocation1, allocation2, allocation3;
//256KB 什么时候进入老年代决定于XX:MaxTenuringThreshold设置
allocation1 = new byte[_1MB / 4];
allocation2 = new byte[4 * _1MB];//4048KB
allocation3 = new byte[4 * _1MB]; //4048KB eden共占用了 8352KB
allocation3 = null; //断开引用,成为垃圾对象
//再申请分配4MB内存,放不下,触发Minor GC
allocation3 = new byte[4 * _1MB];
}
}
1.2、日志
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 896768 bytes, 896768 total
: 6079K->875K(9216K), 0.0036167 secs] 6079K->4971K(19456K), 0.0036538 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 584 bytes, 584 total
: 5056K->0K(9216K), 0.0008881 secs] 9152K->4968K(19456K), 0.0009051 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4316K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 52% used [0x00000000fec00000, 0x00000000ff037058, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400248, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4968K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 48% used [0x00000000ff600000, 0x00000000ffada120, 0x00000000ffada200, 0x0000000100000000)
Metaspace used 3244K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 353K, capacity 388K, committed 512K, reserved 1048576K
3、分析
3.1、第1次GC前
针对输出结果我们可以拆分来看,当allocation1和allocation2对象加载的时候,两个对象加在一起是4.25MB,Eden区都能存放下(Eden区大小9216K),没有任何问题。
我们看到发生GC前,eden使用空间6079K,其中allocation2使用41024K,allocation1使用256K,那么其他系统使用=6079-41024-256=1727K。
对应内存图如下
3.2、第1次GC
当allocation3对象创建的时候,这时发现eden区空间不足,则会触发第一次GC
3.2.1、日志解读
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 896768 bytes, 896768 total
: 6079K->875K(9216K), 0.0036167 secs] 6079K->4971K(19456K), 0.0036538 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
GC :
代表发生了一次垃圾回收,前面没有Full修饰,表明这时一次Minor GC;
Allocation Failure:
表明本次引起GC的原因是因为在年轻代中没有足够的空间能够存储新的数据了。
6079K->875K(9216K):
三个参数分别为:GC前该内存区域(这里是年轻代)使用容量,GC后该内存区域使用容量,该内存区域总容量。
6079K->4971K(19456K):
三个参数分别为:堆区垃圾回收前的大小,堆区垃圾回收后的大小,堆区总大小。
0.0036167 secs
代表本次新生代GC耗时
年轻代回收空间
6079K-875K=5204K=5.082M
堆回收空间
6079K-4971K=1108K
进入老年代空间
5204K-1108K=4096=4M
3.2.2、 内存变化图
这里请大家注意:由于我们的 allocation1对象和allocation2对象都是强引用不会被回收,所以肯定会直接放入幸存者区域,allocation1对象可以放入,但是我们的allocation2对象太大是无法放入S1区的,因此根据我们上面讲的垃圾收集器的默认担保机制,allocation2对象会直接进入到我们的老年代进行存放。 这也解释了为什么最终有4096K(4MB)大小的对象进入了老年代
当第一次GC完后Eden区就有足够的空间存放 allocation3对象了。
3.2、第2次GC
allocation3 = null; //这行代码一旦执行,那么我们的allotion3对象没有了直接引用者
接着最后一行代码开始执行:
allocation3 = new byte[4 * _1MB]; //再申请分配4MB内存,放不下,触发Minor GC
这次继续申请分配4MB大小对象放入Eden区,那么依然又会存在分配不下触发GC,继续分析如下日志:
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 584 bytes, 584 total
: 5056K->0K(9216K), 0.0008881 secs] 9152K->4968K(19456K), 0.0009051 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
那么我们本次日志得出的结论:
1、 该次GC新生代减少了5056-0=5056KB;
1、 注意:新生代直接减少到了0!代表所有幸存区S1里的对象全部转移到了老年代!(因为我们的年龄阈值设置的刚好就是1)allocation3对象是直接被回收了;
2、 Heap区总共减少了9152-4968=4184KB;
1、 主要就是我们的allocation3对象以及少量系统对象被回收了;
3、 5056KB-4184KB=872KB代表一共有872KB对象从年轻代转移到了老年代;
最后内存结果如下:
跟我们最后的内存日志结果匹配
Heap
def new generation total 9216K, used 4316K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 52% used [0x00000000fec00000, 0x00000000ff037058, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400248, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 4968K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 48% used [0x00000000ff600000, 0x00000000ffada120, 0x00000000ffada200, 0x0000000100000000)