大对象直接进入老年代

《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》第 3 章垃圾收集器与内存分配策略,本章介绍了垃圾收集的算法、几款 JDK 1.6 中提供的垃圾收集器特点及其运作原理。通过代码实例验证了 Java 虚拟机中自动内存分配及回收的主要规则。本节为大家介绍大对象直接进入老年代。
摘自:《深入理解 Java 虚拟机:JVM 高级特性与最佳实践》第 3 章垃圾收集器与内存分配策略,本章介绍了垃圾收集的算法、几款 JDK 1.6 中提供的垃圾收集器特点及其运作原理。通过代码实例验证了 Java 虚拟机中自动内存分配及回收的主要规则。本节为大家介绍大对象直接进入老年代。
3.5.2 大对象直接进入老年代

所谓大对象就是指,需要大量连续内存空间的 Java 对象,最典型的大对象就是那种很长的字符串及数组(笔者例子中的 byte[]数组就是典型的大对象)。大对象对虚拟机的内存分配来说就是一个坏消息(替 Java 虚拟机抱怨一句,比遇到一个大对象更加坏的消息就是遇到一群“朝生夕灭”的“短命大对象”,写程序的时候应当避免),经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间来“安置”它们。

虚拟机提供了一个-XX:PretenureSizeThreshold 参数,令大于这个设置值的对象直接在老年代中分配。这样做的目的是避免在 Eden 区及两个 Survivor 区之间发生大量的内存拷贝(复习一下:新生代采用复制算法收集内存)。

执行代码清单 3-4 中的 testPretenureSizeThreshold()方法后,我们看到 Eden 空间几乎没有被使用,而老年代 10MB 的空间被使用了 40%,也就是 4MB 的 allocation 对象直接就分配在老年代中,这是因为 PretenureSizeThreshold 被设置为 3MB(就是 3145728B,这个参数不能与-Xmx 之类的参数一样直接写 3MB),因此超过 3MB 的对象都会直接在老年代中进行分配。

注意 PretenureSizeThreshold 参数只对 Serial 和 ParNew 两款收集器有效,Parallel Scavenge 收集器不认识这个参数,Parallel Scavenge 收集器一般并不需要设置。如果遇到必须使用此参数的场合,可以考虑 ParNew 加 CMS 的收集器组合。

代码清单 3-4 大对象直接进入老年代

  1. private static final int _1MB = 1024 * 1024;
  2. /**
    • VM 参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
    • -XX:PretenureSizeThreshold=3145728
  3. */
  4. public static void testPretenureSizeThreshold() {
  5.  byte[] allocation;
  6.  allocation = new byte[4 * _1MB]; // 直接分配在老年代中
  7. }

运行结果:

  1. Heap
  2. def new generation total 9216K, used 671K
    [0x029d0000, 0x033d0000, 0x033d0000)
  3. eden space 8192K, 8% used [0x029d0000,
    0x02a77e98, 0x031d0000)
  4. from space 1024K, 0% used [0x031d0000, 0x031d0000, 0x032d0000)
  5. to space 1024K, 0% used [0x032d0000, 0x032d0000, 0x033d0000)
  6. tenured generation total 10240K, used 4096K
    [0x033d0000, 0x03dd0000, 0x03dd0000)
  7. the space 10240K, 40% used [0x033d0000,
    0x037d0010, 0x037d0200, 0x03dd0000)
  8. compacting perm gen total 12288K, used 2107K
    [0x03dd0000, 0x049d0000, 0x07dd0000)
  9. the space 12288K, 17% used [0x03dd0000,
    0x03fdefd0, 0x03fdf000, 0x049d0000)
  10. No shared spaces configured.