关于java:JVM对象进入老年代的四种方式1实战篇

16次阅读

共计 2628 个字符,预计需要花费 7 分钟才能阅读完成。

对象进入老年代的四种形式

  • 大对象
  • 动静年龄判断
  • minor gc 后,survivor 区空间不能包容全副存活对象
  • 存活对象达到年龄阈值。比方 15

这一节次要讲:minor gc 后,survivor 区空间不能包容全副存活对象

间接上代码:

private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {byte[] array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];

        byte[] array2 = new byte[128*1024];
        array2 = null;


        byte[] array3 = new byte[2*_1MB];// 这里触发第一次 minor gc
    }

JVM 参数:

-XX:NewSize=10m -XX:MaxNewSize=10m -XX:InitialHeapSize=20m -XX:MaxHeapSize=20m -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10m -XX:MaxTenuringThreshold=15 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:survivor_live.log

运行代码后的日志信息:

Java HotSpot(TM) 64-Bit Server VM (25.281-b09) for bsd-amd64 JRE (1.8.0_281-b09), built on Dec  9 2020 12:44:49 by "java_re" with gcc 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)
Memory: 4k page, physical 16777216k(107748k free)

/proc/meminfo:

CommandLine flags: -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=15 -XX:NewSize=10485760 -XX:OldPLABSize=16 -XX:PretenureSizeThreshold=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 

0.127: [GC (Allocation Failure) 0.127: [ParNew: 6943K->327K(9216K), 0.0030105 secs] 6943K->2377K(19456K), 0.0032581 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 par new generation   total 9216K, used 2458K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  26% used [0x00000007bec00000, 0x00000007bee14930, 0x00000007bf400000)
  from space 1024K,  32% used [0x00000007bf500000, 0x00000007bf551fb8, 0x00000007bf600000)
  to   space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
 concurrent mark-sweep generation total 10240K, used 2050K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 2713K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 291K, capacity 386K, committed 512K, reserved 1048576K

接下来,咱们来剖析代码和日志:

byte[] array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];// 假如这个是 C 对象

        byte[] array2 = new byte[128*1024];
        array2 = null;

这里创立了 3 个 2m 对象,1 个 128k 的对象。最终 array1 指向 C 对象,array2 置为 null。对应的堆图如下所示:

此时日志所示:
ParNew: 6943K->327K(9216K)

这个时候 eden 区已应用 6943K。

此时要执行 byte[] array3 = new byte[2*_1MB];

这个时候因为可应用空间只有 8m,如果要调配 2m 空间,此时会触发 young gc。

ParNew: 6943K->327K(9216K)

因为只有 array1 指向了 1 一个 2M 对象,其余对象都会被回收掉。

GC 后,新生代只剩下 327K。这个时候你可能会问:2m 对象去哪里了呢?

concurrent mark-sweep generation total 10240K, used 2050K

你看,2m 对象在老年代中。为什么会在老年代中。

因为新生代调配了 10m 空间,而后 survivor 区只占 1m 空间。

1m 的空间是无奈包容 2m 的对象的。

因而,对象间接进入老年代。

说到这里,咱们曾经简略 地用代码证实了:minor gc 后,survivor 区空间不能包容全副存活对象

有一些仔细的同学可能会问:当 survivor 空间有余时,存活对象都全副进入老年代吗?survivor 区能包容的对象,可否放在 survivor 区,不能包容的对象,才放到老年代。

这个问题,咱们后续会有专门文章解答。大家先思考一下。

正文完
 0