【JVM】详解Java 堆内存分区

Java 堆内存(Heap Memory)是 Java 虚拟机(JVM)中用于存储对象实例的区域。为了更有效地管理和回收内存,Java 堆通常被划分为不同的区域,每个区域有特定的用途和特点。以下是 Java 堆内存分区的定义、作用以及相关的示例。

Java 堆内存分区

Java 堆通常被分为三大区域:

  1. 年轻代(Young Generation)
  2. 老年代(Old Generation)
  3. 永久代(Permanent Generation) / 元空间(Metaspace)
1. 年轻代(Young Generation)

定义:

年轻代用于存储新创建的对象。这一代又进一步划分为三个区域:Eden 区、Survivor From 区和 Survivor To 区。

作用:

  • Eden 区:大多数新创建的对象首先在 Eden 区分配内存。
  • Survivor From 区和 Survivor To 区:用于存活对象的复制。在垃圾回收过程中,存活的对象从一个 Survivor 区复制到另一个 Survivor 区或移动到老年代。

垃圾回收:

年轻代采用的是 Minor GC(小型垃圾回收)。由于大多数对象在创建后很快就变得不可达,Minor GC 可以快速回收这些对象。

示例:

java 复制代码
public class YoungGenerationExample {
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            // 创建短生命周期的对象,分配在 Eden 区
            byte[] array = new byte[1024 * 1024];
        }
    }
}

在这个示例中,大量短生命周期的对象被创建并分配在 Eden 区。

2. 老年代(Old Generation)

定义:

老年代用于存储生命周期较长的对象。经过多次 Minor GC 仍然存活的对象会被移到老年代。

作用:

老年代用于存储生命周期较长的对象,这些对象不容易被回收。

垃圾回收:

老年代采用的是 Major GC(也称为 Full GC)。由于老年代的对象存活率较高,Major GC 的频率较低但耗时较长。

示例:

java 复制代码
public class OldGenerationExample {
    public static void main(String[] args) {
        // 创建生命周期较长的对象
        byte[] array = new byte[10 * 1024 * 1024];
        // 让对象存活,防止被回收
        while (true) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这个示例中,创建了一个生命周期较长的大对象,最终会被移动到老年代。

3. 永久代(Permanent Generation)和元空间(Metaspace)

定义:

永久代和元空间用于存储类元数据(class metadata)、常量池、静态变量和 JIT 编译后的代码。

  • 永久代(Permanent Generation):用于存储类元数据和其他与类有关的结构。在 Java 8 之前,永久代是方法区的实现。
  • 元空间(Metaspace):从 Java 8 开始,永久代被元空间取代。元空间使用本地内存(native memory)而不是堆内存。

作用:

  • 永久代:存储类信息、常量、静态变量和方法数据。
  • 元空间:更灵活地管理类元数据,避免了永久代的固定大小限制。

示例:

java 复制代码
public class MetaspaceExample {
    public static void main(String[] args) {
        // 创建大量类加载操作,增加元空间的使用
        for (int i = 0; i < 10000; i++) {
            ClassLoader loader = new DynamicClassLoader();
            try {
                Class<?> clazz = loader.loadClass("example.MyClass" + i);
                Object instance = clazz.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

class DynamicClassLoader extends ClassLoader {
    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = loadClassData(name);
        return defineClass(name, b, 0, b.length);
    }

    private byte[] loadClassData(String name) {
        // 动态生成字节码
        return new byte[0];
    }
}

在这个示例中,通过动态类加载器创建大量类,增加元空间的使用。

总结

  • 年轻代:存储新创建的对象,包含 Eden 区和两个 Survivor 区,进行 Minor GC。
  • 老年代:存储生命周期较长的对象,进行 Major GC。
  • 永久代 / 元空间:存储类元数据,Java 8 之后使用元空间,避免了永久代的固定大小限制。

理解 Java 堆内存分区有助于优化应用程序性能和有效管理内存资源。

相关推荐
2401_8955213410 分钟前
springboot集成onlyoffice(部署+开发)
java·spring boot·后端
zlpzlpzyd11 分钟前
groovy学习
java·jvm·学习
程序员小假20 分钟前
你分得清 Prompt、Agent、Function Call、Skill、MCP 吗?
java·后端
xuboyok223 分钟前
【Spring Boot】统一数据返回
java·spring boot·后端
亚马逊云开发者25 分钟前
你的 AI Agent 只有鱼的记忆?聊聊 Agent 记忆管理的正确姿势
java
燕山罗成1 小时前
JAVA多线程基础
java·开发语言
予枫的编程笔记1 小时前
【面试专栏|Java并发编程】拆解Java线程生命周期:从新建到终止,再讲清进程与线程的核心差异
java·多线程·java基础·java面试·进程与线程·面试干货·java线程生命周期
是梦终空1161 小时前
Python深度学习入门:TensorFlow 2.0/Keras实战
jvm·数据库·python
Yvonne爱编码1 小时前
JAVA数据结构 DAY7-二叉树
java·开发语言·数据结构
程序媛徐师姐1 小时前
Java基于微信小程序的球馆预约系统,附源码+文档说明
java·微信小程序·球馆预约系统小程序·jav球馆预约系统小程序·java球馆预约微信小程序·球馆预约微信小程序·java球馆预约系统