jvm内存划分
在Java编程中,Java虚拟机(JVM)内存划分是一个重要的概念。它涉及到JVM在运行Java程序时如何管理内存的问题。JVM内存划分主要分为以下几个部分:
-
堆内存(Heap Memory): 堆是JVM中用于存储对象实例的内存区域。它被所有线程共享,用于存储Java对象,包括实例变量和数组。堆内存又分为新生代(Young Generation)和老年代(Old Generation)。
-
新生代:新创建的对象首先被分配到新生代,其中又分为Eden区和两个Survivor区(通常称为S0和S1)。大多数对象在新生代被快速分配和释放,不经过复杂的垃圾回收过程。
-
老年代:经过多次垃圾回收后仍然存活的对象会被晋升到老年代。老年代用于存储生命周期较长的对象,垃圾回收发生在老年代的频率较低。
-
-
方法区(Method Area): 方法区用于存储类的元数据,包括类的信息、字段、方法、常量池等。在较新的JVM实现中,方法区被称为元空间(Metaspace),它通常不限制于物理内存,可以通过设置参数来控制其大小。
-
虚拟机栈(VM Stack): 每个线程在运行时都有一个私有的虚拟机栈,用于存储方法调用的局部变量、操作数栈、动态链接、方法出口等。栈帧用于存储每个方法的状态。
-
本地方法栈(Native Method Stack): 与虚拟机栈类似,但用于执行Native方法(即非Java代码)的调用。
-
程序计数器(Program Counter): 每个线程都有一个程序计数器,用于指示下一条将要执行的指令。在多线程环境下,程序计数器确保线程切换后能够正确恢复执行。
需要注意的是,具体的内存划分可以因不同的JVM实现和配置而有所不同。可以通过调整JVM的启动参数来控制各个内存区域的大小,以适应不同的应用场景和需求。
说白了,主要其实就是包含三个区:
1、对象堆
新生代:新创建8:幸存区1:幸存区1。
老年代:生命周期长的对象,就放到老年代。
2、线程栈
方法的局部变量。生命周期随着方法的开始而开始,随着方法的结束而结束。
3、元数据/方法区
类本身的信息,类的字段和类的方法。
类的静态数据,常量数据。
静态数据属于哪个区
静态数据通常属于方法区(或元空间,取决于JVM的实现)。方法区用于存储类的元数据,包括类的信息、字段、方法、常量池等。静态成员变量和静态方法属于类本身,不依赖于类的实例,因此它们的信息被存储在方法区中。这些信息在类加载时被加载到方法区,并在整个程序运行期间保持不变。
示意图
---------------------------
| 方法区(元空间) |
---------------------------
| 虚拟机栈(Thread 1) |
---------------------------
| 虚拟机栈(Thread 2) |
---------------------------
| ... |
---------------------------
| 本地方法栈(Thread 1)|
---------------------------
| 本地方法栈(Thread 2)|
---------------------------
| ... |
---------------------------
| 堆内存(Heap) |
| |-----------------------| |
| | 新生代(Eden) | |
| |-----------------------| |
| | 幸存者区(S0 / S1) | |
| |-----------------------| |
| | 老年代(Old) | |
| |-----------------------| |
---------------------------
| 程序计数器(PC) |
---------------------------
请注意,这只是一个示意图,实际情况可能会因JVM实现、配置和应用程序的不同而有所变化。图中的各个区域代表了不同的内存区域,包括方法区(或元空间)、虚拟机栈、本地方法栈、堆内存和程序计数器。不同的线程会在各自的虚拟机栈和本地方法栈中执行,堆内存包含了新生代和老年代等不同的分区。方法区存储类的元数据。