Skip to content

Latest commit

 

History

History
145 lines (96 loc) · 4.97 KB

11-内存分配与回收策略案例.md

File metadata and controls

145 lines (96 loc) · 4.97 KB

11-内存分配与回收策略案例

对象优先在Edon区域分配

示例程序

  • JVM配置参数 : 堆内存设置为20M; 年轻代10M; Edon:Survivor from:Survivor to = 8:1:1 即 8M:1M:1M
-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
  • Java环境
jdk1.8.0_202
  • 程序代码
public class MinorGCDemo {
    private static final int _1M = 1024 * 1024;
    public static void main(String[] args){
        byte[] arr1, arr2, arr3, arr4;
        arr1 = new byte[2 * _1M];  // 分配到 Edon
        arr2 = new byte[2 * _1M];  // 分配到 Edon
        arr3 = new byte[2 * _1M];  // 分配到 Edon
        /*
        Edon 只剩2M了,空间不足,引发 Minor GC;
        Minor GC时(Edon--》Survivor时),发现Survivor可用空间只有1M,3个2M的对象无法回收;
        因此这三个对象会放到老年代(老年代占用6M);
        Edon空出来,分配arr4,此时Edon占用空间4M;
         */
        arr4 = new byte[4 * _1M];  

    }
}

运行结果

[GC (Allocation Failure) [PSYoungGen: 7535K->999K(9216K)] 7535K->3842K(19456K), 0.0021218 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 9216K, used 5419K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 53% used [0x00000000ff600000,0x00000000ffa511a0,0x00000000ffe00000)
  from space 1024K, 97% used [0x00000000ffe00000,0x00000000ffef9c28,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6939K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 67% used [0x00000000fec00000,0x00000000ff2c6c20,0x00000000ff600000)
 Metaspace       used 3202K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 345K, capacity 388K, committed 512K, reserved 1048576K

分析GC日志结果

  • [GC (Allocation Failure) [PSYoungGen: 7535K->999K(9216K)] 7535K->3842K(19456K), 0.0021218 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

    • arr4 = new byte[4 * _1M]; 分配空间失败,则发生minor gc;
  • ParOldGen total 10240K, used 6939K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)

    • Edon已经占用了6M,空间不足以分配,Survivor可用也只有1M,所以arr1、arr2、arr3 被通过分配担保机制分配到老年代中
  • eden space 8192K, 53% used [0x00000000ff600000,0x00000000ffa511a0,0x00000000ffe00000)

    • Edon空出来,分配4M空间给arr4

所以运行完 arr4 = new byte[4 * _1M]; 这行代码时:

堆空间内存:

Edon: 总空间8M 占用4M 存放arr4

老年代: 总空间10M 占用6M 存放arr1、arr2、arr3

大对象直接分配在老年代

示例程序

  • JVM配置参数 : 堆内存设置为20M; 年轻代10M; Edon:Survivor from:Survivor to = 8:1:1 即 8M:1M:1M
  • -XX:PretenureSizeThreshold=3145728 : 单位字节,大于这个值的对象直接分配到老年代
-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728  
  • Java环境
jdk1.8.0_202
  • 程序代码
/**
 -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
 */
public class PretenureSizeThresholdDemo {

    private static final int _1M = 1024 * 1024;
    public static void main(String[] args){
        byte[] arr = new byte[_1M];
    }
}

运行结果

Heap
 PSYoungGen      total 9216K, used 5651K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 68% used [0x00000000ff600000,0x00000000ffb84f20,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff000010,0x00000000ff600000)
 Metaspace       used 3254K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 347K, capacity 388K, committed 512K, reserved 1048576K

分析GC日志结果

我们没有看到GC,但是老年代已经占用了4M空间:

  • ParOldGen total 10240K, used 4096K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
    • 这就是指定了的 -XX:PretenureSizeThreshold=3145728 大于这个值的对象直接分配到了老年代

长期存活的对象将进入老年代

JVM给每一个对象定义了一个对象年龄计数器

如果对象在Edon出生并且经过第一次Minor GC后仍然存活,并且能够被Survivor容纳,将被移动到Survivor空间中,将对象年龄设置为1.