【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 堆内存分区有助于优化应用程序性能和有效管理内存资源。

相关推荐
待磨的钝刨几秒前
【格式化查看JSON文件】coco的json文件内容都在一行如何按照json格式查看
开发语言·javascript·json
XiaoLeisj2 小时前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
paopaokaka_luck2 小时前
【360】基于springboot的志愿服务管理系统
java·spring boot·后端·spring·毕业设计
dayouziei2 小时前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师3 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉3 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer3 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq4 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
Yaml44 小时前
Spring Boot 与 Vue 共筑二手书籍交易卓越平台
java·spring boot·后端·mysql·spring·vue·二手书籍
小小小妮子~4 小时前
Spring Boot详解:从入门到精通
java·spring boot·后端