1、vm运行参数

-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+PrintHeapAtGC
package com.memory.gc;

public class TestAllocation {

    private static final int _1MB = 1024* 1024;

    public static void testAllocation(){
        byte[] allocation,allocation2,allocation3,allocation4;
        allocation = new byte[2*_1MB];
        allocation2 = new byte[2*_1MB];
        allocation3 = new byte[2*_1MB];
        allocation4 = new byte[4*_1MB];
    }

    public static void main(String[] args) {
        TestAllocation.testAllocation();
    }
}

日志打印

{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 6423K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc45fa0,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 Metaspace       used 3459K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 379K, capacity 388K, committed 512K, reserved 1048576K
2018-08-20T18:49:20.533+0800: [GC (Allocation Failure) [PSYoungGen: 6423K->808K(9216K)] 6423K->4912K(19456K), 0.0023385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3459K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 379K, capacity 388K, committed 512K, reserved 1048576K
}
Heap
 PSYoungGen      total 9216K, used 7273K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 78% used [0x00000000ff600000,0x00000000ffc50688,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3471K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 381K, capacity 388K, committed 512K, reserved 1048576K

·-Xms20M -Xmx20M -Xmn10M这3个参数限制了Java堆大小为20MB,不可扩展,其中10MB分配给新生代,剩下的10MB分配给老年代。-XX:SurvivorRatio=8定义了新生代中Eden区与一个Survivor区的空间比例是8:1,从输出结果也可以清晰的看到”eden space 8192K、from space 1024K、to space 1024K”的信息,新生代总可用空间为9216KB(Eden区+1个Survivor区的总容量)。
执行to space 1024K中分配allocation4对象的语句时会发生一次Minor GC:

  • 日志最开始的GC和Full GC表示垃圾回收的停顿类型;
  • PSYoungGen中最前面的PS代表垃圾收集器是Parallel Scavenge收集器,回收的区域是新生代(YoungGen);
  • ParOldGen中最前面的Par代表垃圾收集器是Parallel Old收集器,回收的区域是老年代(OldGen);
  • total 9216K, used 6423K中total表示总共可使用内存,userd表示使用内存
    根据深入理解JAVA虚拟机一书描述,JDK版本1.7,在申请4M内存时由于年轻代空间不足需要进行GC,将allocation,allocation2,allocation3移至老年代,然后将allocation4放入年轻代,所以年轻代4M空间,老年代6M。
    JDK升级到1.8后现象有所有不同,可以看到年轻代最后是6M空间,老年代是4M空间,此现象由于更新了GC收集器

重头戏

2018-08-20T18:49:20.533+0800: [GC (Allocation Failure) [PSYoungGen: 6423K->808K(9216K)] 6423K->4912K(19456K), 0.0023385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 9216K, used 808K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 0% used [0x00000000ff600000,0x00000000ff600000,0x00000000ffe00000)
  from space 1024K, 78% used [0x00000000ffe00000,0x00000000ffeca020,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 4104K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 40% used [0x00000000fec00000,0x00000000ff002020,0x00000000ff600000)
 Metaspace       used 3459K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 379K, capacity 388K, committed 512K, reserved 1048576K
}
  • [PSYoungGen: 6423K->808K(9216K)]年轻代释放后为808K
  • PSYoungGen:6423K->4912K(19456K)总内存释放后为4912K
  • eden space 8192K, 0%
  • from space 1024K, 78% used
  • ParOldGen total 10240K, used 4104K

现在出现了一个问题,数据对不上了,原来6423K数据,现在4912K,数据少了,原因如下:
并行收集器组合 Parallel Scavenge + Parallel Old年轻代采用复制算法,老年代采用标记-整理,在回收的同时还会对内存进行压缩。
4912K = 4104K + 1024K * 78%

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐