一个Java进程占用的内存都哪些部分?
1 个回答
慢慢理解世界,慢慢更新自己。大龙### **1. Java 进程的主要内存区域** Java 进程运行时,会占用多块不同的内存区域,主要包括: 1. **JVM 内存** - Java 堆(Heap) - Java 虚拟机栈(JVM Stack) - 本地方法栈(Native Method Stack) - 方法区(Method Area,包括元空间 Metaspace) - 运行时常量池(Runtime Constant Pool) - 代码缓存区(Code Cache) 2. **堆外内存** - 直接缓冲区(Direct Buffer) - 压缩类空间(Compressed Class Space) - 代码缓冲区(Code Cache) 3. **非 JVM 内存** - 本地运行库(Native Libraries) - JNI(Java Native Interface) ### **2. JVM 内存区域** JVM 运行时的内存区域包括堆、方法区、栈等: #### **(1) Java 堆(Heap)** - **作用**:存储对象实例,几乎所有对象都在这里分配。 - **特点**: - JVM 运行时**占用内存最大**的区域。 - **线程共享**。 - 由垃圾回收器(GC)管理。 - **结构**: - **年轻代(Young Generation)** - **Eden 区**:新对象首先分配在这里。 - **Survivor 区(S0/S1)**:用于存活对象的短期存储。 - **老年代(Old Generation)**:存储长生命周期对象。 #### **(2) 虚拟机栈(JVM Stack)** - **作用**:存储方法执行时的局部变量、操作数栈、方法出口等信息。 - **特点**: - **线程私有**。 - 方法调用时,JVM 会在栈中创建 **栈帧(Stack Frame)**。 - **方法执行完后,栈帧销毁**,数据立即释放。 - **常见错误** - **栈溢出(StackOverflowError)**:递归调用过深导致栈空间耗尽。 - **堆溢出(OutOfMemoryError: unable to create new native thread)**:线程数超出系统限制。 #### **(3) 本地方法栈(Native Method Stack)** - **作用**:存储调用 JNI(Java Native Interface)方法时的本地变量和参数。 - **特点**: - **线程私有**。 - **调用 C/C++ 本地代码**(如 `System.loadLibrary()`)。 - **异常** - **StackOverflowError**:本地方法递归过深。 - **OutOfMemoryError**:本地方法栈耗尽。 #### **(4) 方法区(Method Area,包括元空间 Metaspace)** - **作用**:存储类的元信息,如类名、字段、方法、常量池等。 - **特点**: - **线程共享**。 - **JDK 1.8 及之后,方法区实现为元空间(Metaspace)**。 - **元空间使用的是堆外内存**,由操作系统管理,不再受 `MaxPermSize` 限制。 - **异常** - **OutOfMemoryError: Metaspace**:元空间溢出,通常是动态加载类过多导致。 #### **(5) 运行时常量池(Runtime Constant Pool)** - **作用**:存储编译期产生的常量信息(字符串、方法引用、字段引用等)。 - **特点**: - **属于方法区的一部分**。 - **存储字符串常量池**(`String.intern()`)。 - **异常** - **OutOfMemoryError**:常量池存储过多数据,导致方法区溢出。 #### **(6) 代码缓冲区(Code Cache)** - **作用**:存储 JIT(即时编译器)编译后的机器码,避免重复编译。 - **特点**: - **线程共享**。 - 提高 JVM 执行效率。 - **异常** - **CodeCache is full**:JIT 编译过多方法,导致代码缓存溢出。 ### **3. 堆外内存** #### **(1) 直接缓冲区(Direct Buffer)** - **作用**:Java NIO(New I/O)使用 `ByteBuffer.allocateDirect()` 分配的堆外内存。 - **特点**: - **减少 Java 堆和操作系统之间的数据拷贝,提高 IO 效率**。 - **避免 GC 影响**,但需要手动释放,否则可能导致 `OutOfMemoryError: Direct buffer memory`。 #### **(2) 压缩类空间(Compressed Class Space)** - **作用**:存储类元数据指针,减少指针占用的内存。 - **特点**: - **元空间的一部分**。 - **仅在 64 位 JVM 下生效**,使用 32 位指针来减少内存占用。 #### **(3) 代码缓冲区(Code Cache)** - **作用**:存储 JIT 编译的机器码,提高方法执行效率。 - **特点**: - **优化热点代码**。 - **减少解释执行的开销**。 ### **4. 非 JVM 内存** #### **(1) 本地运行库(Native Libraries)** - **作用**:存储 C/C++ 语言编写的动态库,如 `libc.so`、`.dll`。 - **特点**: - 由 `System.loadLibrary()` 加载。 - JVM 运行时需要调用操作系统 API 时使用。 #### **(2) JNI(Java Native Interface)** - **作用**:允许 Java 代码调用 C/C++ 代码。 - **特点**: - 提供跨语言调用能力。 - 例如:Java 访问 OpenGL、调用底层网络 API。 ### **5. Java 进程的内存结构总结** | **内存区域** | **作用** | **是否线程共享** | **异常** | |-----------|---------|---------|---------| | **堆(Heap)** | 存储对象实例 | ✅ 共享 | `OutOfMemoryError: Java heap space` | | **虚拟机栈(JVM Stack)** | 方法调用时存储局部变量 | ❌ 线程私有 | `StackOverflowError` | | **本地方法栈(Native Method Stack)** | 存储 JNI 调用数据 | ❌ 线程私有 | `StackOverflowError` | | **方法区(Metaspace)** | 存储类元信息 | ✅ 共享 | `OutOfMemoryError: Metaspace` | | **运行时常量池(Runtime Constant Pool)** | 存储常量信息 | ✅ 共享 | `OutOfMemoryError` | | **代码缓冲区(Code Cache)** | 存储 JIT 编译的代码 | ✅ 共享 | `CodeCache is full` | | **直接缓冲区(Direct Buffer)** | 提高 NIO 读写效率 | ✅ 共享 | `OutOfMemoryError: Direct buffer memory` | | **压缩类空间(Compressed Class Space)** | 64 位 JVM 下优化指针 | ✅ 共享 | 可能会导致 `Metaspace OOM` | | **本地运行库(Native Libraries)** | 存储 `.so` / `.dll` 文件 | ✅ 共享 | - | ### **6. 结论** - **JVM 进程主要占用**: - **JVM 内存**(堆、栈、方法区、运行时常量池)。 - **堆外内存**(直接缓冲区、代码缓冲区)。 - **非 JVM 内存**(本地库、JNI)。 - **JDK 1.8 之后,方法区被 Metaspace 取代**,使用堆外内存,减少 `PermGen` OOM 问题。 - **云原生应用可以使用 AOT 编译减少堆内存占用,提高启动速度**。发布于 2025-03-16 13:09 •IP属地 海南举报评论收藏
公众号进入网站体验更佳

