新生代 老年代 元空间
在Java虚拟机(JVM)中,"新生代"和"老年代"是堆内存的两个不同区域,而"元空间"则是一个用于存储类元数据的区域。
- 新生代(Young Generation):
新生代主要存放的是新创建的对象。它又分为三个部分:
Eden区:大部分新对象会首先分配在这里。
两个Survivor区:它们被称为S0和S1,在垃圾回收过程中用来存放从Eden区复制过来的存活对象。
新生代的特点是对象存活时间较短,垃圾回收频繁,使用的是Minor GC(小型垃圾回收)。
- 老年代(Old Generation):
老年代存放的是生命周期较长的对象。经过多次垃圾回收后,存活下来的对象会被移动到老年代。
当老年代的内存空间不足时,会触发Major GC或Full GC(完全垃圾回收)。老年代的垃圾回收次数较少,但每次回收都可能更加耗时。
- 元空间(Metaspace):
元空间存储的是类的元数据,比如类的结构信息、方法信息等。元空间取代了JVM早期的永久代(PermGen),它不再使用堆内存,而是直接使用本地内存。
元空间的大小默认是动态调整的,但也可以通过JVM参数进行限制。
垃圾回收算法
- 标记-清除算法(Mark-and-Sweep)
标记阶段:遍历堆中的所有对象,标记出哪些对象是可达的(即程序中仍然被引用的对象)。
清除阶段:清理掉所有未被标记的对象,即不再使用的对象。
缺点:
可能会产生内存碎片,因为清除后的空间并不连续。
需要额外的时间来遍历整个堆和清理无用对象。
- 复制算法(Copying)
将内存分为两个区域(通常是"From"和"To"区),每次只使用一个区域。当一个区域满了时,复制存活的对象到另一个区域,并清空当前区域。
复制算法解决了标记-清除算法的内存碎片问题。
优点:
没有内存碎片。
复制时速度较快。
缺点:
需要两倍的内存空间,因为需要维护两个区域。
对象复制操作会带来额外的性能开销。
- 标记-整理算法(Mark-Compact)
标记阶段:与标记-清除算法相同,标记出可达对象。
整理阶段:对标记的存活对象进行压缩,所有存活对象移动到堆的一端,腾出的空间将被回收。
优点:
解决了内存碎片的问题。
缺点:
移动对象会带来一定的性能开销,尤其是在老年代中对象比较多时。
- 分代收集算法(Generational Collection)
这是Java垃圾回收中最常用的算法。它基于对象的生命周期分为新生代和老年代。
新生代:大多数对象很快会变得不可达,因此使用复制算法(如Minor GC)来回收新生代。
老年代:较少的对象会存活较长时间,因此使用标记-整理算法或标记-清除算法来回收老年代。
优点:
通过将对象分代来提高效率,因为大多数对象会在新生代中快速死亡,减少了垃圾回收的开销。
新生代和老年代分别采用不同的回收策略,优化了内存使用。
- 垃圾回收器的种类
Serial GC:单线程的垃圾回收器,适合单核处理器或低内存的环境,采用复制算法。
Parallel GC:多线程的垃圾回收器,适用于多核处理器,使用并行方式处理新生代的垃圾回收。
CMS (Concurrent Mark-Sweep) GC:并发标记-清除算法,能够在应用程序运行时进行垃圾回收,减少停顿时间,但会导致内存碎片问题。
G1 (Garbage-First) GC:相较于CMS,G1 GC采用分区化的方式进行垃圾回收,能够更精确地控制停顿时间,适合大内存环境。
ZGC和Shenandoah GC:这些是低延迟的垃圾回收器,旨在最大限度地减少GC暂停时间,适用于低延迟要求较高的应用。
通过这些算法的结合使用,JVM可以在执行期间自动进行垃圾回收,优化内存管理和程序性能。
两个Survivor区的区别
在Java虚拟机(JVM)中新生代(Young Generation)内存区域中,有两个Survivor区,分别称为S0(Survivor 0)和S1(Survivor 1)。这两个区域的作用基本相同,它们之间的区别在于它们的用途和在垃圾回收过程中的角色。
Survivor区的基本概念
新生代的内存划分包括以下三个区域:
Eden区:新创建的对象首先分配到Eden区。
Survivor 0区(S0):存放从Eden区存活下来的对象。
Survivor 1区(S1):存放经过多次垃圾回收后仍然存活的对象。
在一次垃圾回收周期中,Eden区中的存活对象会被复制到Survivor 0区(S0),而S0区中的存活对象在下一轮回收时会被复制到S1区,依此类推。
S0区和S1区的区别
- 用途:
S0区和S1区都是用来存放从Eden区存活下来的对象的。
在每次Minor GC(新生代垃圾回收)时,这两个Survivor区会交替作为存储区域。
- 角色交替:
在一次垃圾回收后,S0区中的存活对象会被复制到S1区,并且下一次垃圾回收时,S1区会充当"From"区,S0区会作为"To"区,存放存活的对象。
每次垃圾回收后,S0和S1会交换角色,确保对象在这些区之间轮换,以避免内存碎片。
- 内存分配:
S0区和S1区的大小在JVM启动时通常是相等的,可以通过JVM参数进行调整。具体的分配和使用策略取决于JVM实现。
- 垃圾回收过程:
Minor GC:新生代的垃圾回收过程通常涉及Eden区和其中一个Survivor区(比如S0)的交替使用。存活的对象会被复制到另一个Survivor区(S1)。这样可以减少对象的复制和内存碎片。
老年代的回收(Major GC):老年代的垃圾回收不会涉及这两个Survivor区,而是会处理长时间存活的对象。
- 总结
S0和S1的主要区别在于它们在不同的垃圾回收周期中分别作为存活对象的存储区域,它们的角色是交替的。
在垃圾回收中,Eden区的存活对象会被复制到一个Survivor区,下一次回收时,另一个Survivor区会变成目标区,这样通过交替的方式管理对象的生命周期。
这种设计使得新生代中的对象在回收时更加高效,并且避免了较大的内存碎片问题