java中的那些对象会进入年轻代?

66 阅读3分钟

在 Java 的内存管理中,Java 堆被划分为不同的代(generation),其中包括年轻代(Young Generation)、老年代(Old Generation)和永久代(PermGen,JDK 8 及以后被元数据区 Metaspace 取代)。年轻代又进一步分为 Eden 区和两个 Survivor 区(S0 和 S1)。以下是进入年轻代的对象的一些情况:

1. 新创建的对象

  • 大多数新创建的对象:几乎所有的新对象都是首先在 Eden 区分配内存的。这是因为年轻代的垃圾回收频率较高,能够快速回收不再需要的对象。

2. Eden 区到 Survivor 区的晋升

  • Eden 区中的存活对象:当 Eden 区满了,触发年轻代垃圾回收(Minor GC)时,存活的对象会被复制到一个 Survivor 区。如果对象在垃圾回收过程中一直存活,它会在两个 Survivor 区之间复制,直到满足晋升到老年代的条件。

3. Survivor 区中的对象

  • Survivor 区之间的复制:对象在一个 Survivor 区中存活后,会被复制到另一个 Survivor 区(假设没有晋升到老年代)。这个过程会不断重复,直到对象满足晋升到老年代的条件(通常是对象在 Survivor 区中的年龄达到某个阈值)。

4. 大对象

  • 大对象:某些 JVM 参数(如 -XX:PretenureSizeThreshold)可以控制大对象直接进入老年代,而不是在年轻代分配。但是默认情况下,许多大对象仍然首先在 Eden 区分配,然后根据需要晋升。

年轻代的结构

  • Eden 区:新对象首先分配内存的区域。
  • Survivor 区:分为两个区 S0 和 S1,存活的对象在这两个区之间复制。

晋升到老年代的条件

对象在年轻代存活一段时间后,会被晋升到老年代。这些条件包括:

  • 年龄阈值:对象在 Survivor 区中存活的垃圾回收次数达到一定的阈值(由参数 -XX:MaxTenuringThreshold 控制,默认为 15)。
  • Survivor 区满:如果 Survivor 区满了,部分存活的对象可能会被直接晋升到老年代。

举例说明对象分配过程

  1. 对象分配:当创建一个新对象时,它通常会被分配到 Eden 区。
  2. Eden 区满:当 Eden 区满了,会触发 Minor GC。存活的对象会被移动到 Survivor 区(假设 S0)。
  3. Survivor 区交换:下一次 Minor GC 时,Eden 和 S0 中存活的对象会被复制到 S1。此时,S0 被清空。
  4. 继续复制:这个过程会继续,S0 和 S1 之间交替复制存活对象。
  5. 晋升到老年代:如果对象在 Survivor 区的年龄达到阈值或 Survivor 区满了,存活的对象会被晋升到老年代。

总结

进入年轻代的主要是新创建的对象,以及在 Eden 区和 Survivor 区之间存活和复制的对象。年轻代的垃圾回收频率高,可以快速回收短命对象,从而减少堆内存的占用,提高内存利用率和应用性能。通过合理设置 JVM 参数,可以优化内存分配和垃圾回收策略,提升 Java 应用的性能。