JVM内存主要由以下几个运行时数据区域组成:
- 堆(Heap):用于存储对象实例,由GC管理。
- 方法区(Method Area):用于存储类信息、常量、静态变量等,由JVM垃圾回收器管理。
- 虚拟机栈(VM Stack):用于存储栈帧,由JVM自管理。
- 本地方法栈(Native Method Stack):用于与操作系统交互的方法,由操作系统管理。
- 程序计数器(PC Register):用于记录当前线程所执行的字节码行号,由JVM自管理。
堆和方法区在JVM启动时创建,一直持续到JVM退出。栈和本地方法栈是为每个线程创建的,程序计数器也是每个线程独立维护的。
来看一个简单例子:
我们可以编写一个Java程序,然后使用 VisualVM工具查看其对应的JVM内存区域。
- 编写一个简单的Java程序:
public class Sample {
public static void main(String[] args) {
method1();
method2();
}
public static void method1() {
int a = 10; // 存储在虚拟机栈
String b = "Hello"; // 存储在堆
final double c = 3.14; // 存储在方法区
}
public static void method2() {
long d = 100L; // 存储在虚拟机栈
char e = 'a'; // 存储在方法区
}
}
- 启动VisualVM,通过”VisualVM > Add JMX Connection”连接此Java程序进程。
- 在VisualVM界面可以看到对应的各内存区域的内存使用情况:
- 堆:可以观察对象”Hello”的大小和地址等信息。
- 方法区:可以观察字符串常量”Hello”、final常量3.14的大小和地址信息。
- 虚拟机栈:可以观察栈帧中的基本变量a、d的大小,但是无法看到具体的值。这是因为虚拟机栈的数据是线程私有的。
从这个简单示例可以直观地观察到不同数据会存储在JVM的哪些内存区域。