第2课java_堆区和垃圾回收器
热度🔥:26 免费课程
授课语音
Java堆和垃圾回收器
1. 介绍
Java的堆内存是JVM内存管理的重要对象,主要用于动态分配对象和数组。堆内存的结构可以分为几个区域:
新生代:新生代主要用于存放新创建的对象。新生代又分为:
- Eden区:所有新对象首先分配在这个区域。当Eden区满时,会触发一次MinorGC,速度较快,回收频率也较高。
- Survivor区:用于存储从Eden区复制过来的存活对象,分为S0和S1两个区域,用于进行对象的存活检查和存放。
老年代:当对象在新生代经历多次垃圾回收后仍然存活,它们会被移动到老年代。某些大对象可能会直接分配到老年代。当老年代满时,会触发MajorGC或FullGC,速度较慢,回收频率低。
永久代:在Java8之前,永久代用于存储类的元数据。但由于永久代大小固定,容易出现
OOM
问题,因此在Java8之后被元空间取代。元空间:元空间用于存储类的元数据,使用本地内存,不受堆大小的限制,包括类结构、方法和字段等信息。
图示
垃圾回收算法
常见的垃圾回收算法包括:
标记-清除算法:分为标记和清除两个阶段。首先,从根节点(如静态变量)开始,标记所有可达的对象,然后清除那些不可达对象的内存。虽然实现简单,但可能会产生内存碎片。
复制算法:将内存分为两个区域,将存活的对象从当前区域复制到另一个区域,然后清理当前区域的对象。这种方法减少了内存碎片,但会浪费一些空间。
标记-整理算法:类似于标记-清除,但在清除阶段将存活的对象移到一起,减少内存碎片,这需要额外的时间开销。
分代收集算法:新生代对象生命周期短,使用复制算法;老年代对象生命周期长,使用标记-整理算法。这种策略提高了垃圾回收效率。
并发标记算法:使用三色标记法,将对象分为白色(未被访问)、灰色(已被访问但引用的对象还未被访问)和黑色(已被访问且引用的对象也被访问)。标记过程分为初识标记、并发标记和最终标记三个步骤。
图示
垃圾回收器
不同的垃圾回收器使用不同的算法和策略:
Serial GC:使用复制算法,单线程执行,垃圾回收过程会暂停应用线程。
Parallel GC:结合使用复制和标记-整理算法,多线程执行,减少垃圾回收时间,但同样会导致应用线程暂停。
CMS GC:使用标记-清除和并发标记算法,通过并发标记减少应用线程的停顿时间。
G1 GC:采用分代收集算法,将堆分为多个区域,优先回收垃圾最多的区域,旨在平衡应用线程的停顿时间和吞吐量,是Java8之后的默认回收器。
ZGC:基于并发标记算法的低延迟垃圾回收器,应用线程的停顿时间可预测。从Java15开始,可以通过-XX:+UseZGC切换使用。
2. 代码案例
下面是一个示例代码,通过创建大量对象并使用System.gc()
来触发垃圾回收。通过添加-XX:+PrintGCDetails
参数,可以在控制台中输出垃圾回收的详细信息,以便分析垃圾回收的行为。还可以使用不同的垃圾回收器来观察行为变化,比如使用-XX:+UseG1GC
。
public class GCDemo {
private static final int _1MB = 1024 * 1024; // 定义1MB的常量
static class MemoryObject {
private byte[] memory = new byte[2 * _1MB]; // 创建一个2MB的对象
}
public static void main(String[] args) {
// 1. 创建大对象并观察垃圾回收行为
MemoryObject[] objects = new MemoryObject[10]; // 创建10个MemoryObject数组
for (int i = 0; i < objects.length; i++) {
objects[i] = new MemoryObject(); // 每次循环创建一个2MB的对象
System.out.println("创建对象 " + i);
// 2. 强制垃圾回收
if (i % 2 == 0) { // 每创建两个对象强制垃圾回收一次
System.gc(); // 调用垃圾回收
System.out.println("在创建对象 " + i + " 后强制进行垃圾回收");
}
}
// 3. 程序结束前进行最终的强制垃圾回收
System.gc();
System.out.println("在退出前强制进行最终的垃圾回收");
}
}
这段代码首先定义了一个MemoryObject
类,其中包含一个2MB的字节数组。在main
方法中创建了一个MemoryObject
数组,并在每次创建对象后强制触发垃圾回收。通过控制台输出,可以观察到不同垃圾回收策略对内存的影响,以及垃圾回收的时机和频率。
通过以上内容,相信大家对Java的堆内存和垃圾回收器有了更深入的理解。