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

相关推荐
Forget the Dream21 分钟前
设计模式之迭代器模式
java·c++·设计模式·迭代器模式
咩咩觉主28 分钟前
C# &Unity 唐老狮 No.7 模拟面试题
开发语言·unity·c#
大丈夫在世当日食一鲲29 分钟前
Java中用到的设计模式
java·开发语言·设计模式
A-Kamen33 分钟前
Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
java·spring boot·后端
练川35 分钟前
Stream特性(踩坑):惰性执行、不修改原始数据源
java·stream
一桶39 分钟前
金融级JVM深度调优实战的经验和技巧
jvm
狂奔小菜鸡40 分钟前
Java运行时数据区
java·jvm·后端
trymoLiu1 小时前
SpringBoot 实现 RSA+AES 自动接口解密!
java·spring boot
却道天凉_好个秋1 小时前
c++ 嵌入汇编的方式实现int型自增
开发语言·汇编·c++
ChinaRainbowSea1 小时前
MySQL 索引的数据结构(详细说明)
java·数据结构·数据库·后端·mysql