JVM有什么用?
1. 让Java“一次编写,到处运行”
你写了一个Java程序,在Windows上编译后生成的是 .class 文件(叫“字节码”)。 这个字节码不是直接给电脑CPU看的,而是给 JVM 看的。 只要在 Windows、Mac、Linux 等系统上安装对应的 JVM,它就能把字节码翻译成该系统能执行的指令。 所以你的程序不需要重写,换个地方也能跑!
2. 自动管理内存(会自己“打扫卫生”)
你创建的对象(比如 new Person()),都放在内存里。 当对象没用了(比如变量不再引用它),JVM 会自动回收这块内存,这叫“垃圾回收”(GC)。 你不用手动清理,减少出错,也更安全。
3. 提高程序运行速度(越用越快)
JVM 有个“聪明助手”叫 JIT 编译器(Just-In-Time)。 它会把经常运行的代码(热点代码)直接编译成机器码,下次执行就飞快! 就像你反复读一段文章,后来直接背下来了,读得更快。
4. 保证程序安全
JVM 可以限制程序的行为,比如: 不能随意访问硬盘文件 不能直接操作内存地址 特别适合运行网络下载的代码(比如早期的小程序 Applet),防止恶意行为。
5. 支持多任务同时运行(多线程)
JVM 内部对“多线程”有良好支持。 多个任务(比如一边下载文件,一边响应用户点击)可以并行执行,互不干扰。
JVM内存模型
一句话总结:
JVM 内存模型是 Java 程序运行时的“内存布局”,它把内存分成几个区域,各司其职,管理代码和数据的存储与使用。
就像一间公司有不同的部门(财务、人事、技术),JVM 也把内存划分为多个“区域”,每个区域负责不同的任务。
JVM 主要包含 5 大内存区域
| 区域 | 作用 | 特点 |
|---|---|---|
| 方法区(Method Area) | 存放类信息、常量、静态变量、方法代码等 | 所有线程共享 |
| 堆(Heap) | 存放对象实例(new 出来的对象) | 最大一块,GC 主战场,线程共享 |
| 虚拟机栈(Java Stack) | 每个方法调用时创建栈帧,保存局部变量、参数、返回地址等 | 每个线程私有 |
| 本地方法栈(Native Method Stack) | 类似虚拟机栈,但用于调用 native 方法 | 线程私有 |
| 程序计数器(PC Register) | 记录当前线程执行到哪一行代码 | 最小,线程私有 |
详细通俗解释
1. 堆(Heap)—— 对象的“大宿舍”
- 所有通过
new创建的对象都住在这里。 - 是 JVM 中最大的一块内存。
- 被所有线程共享(大家都能访问同一个对象)。
- 垃圾回收器(GC)主要工作地:自动清理不再使用的对象。
📌 示例:
Person p = new Person(); // new Person() 这个对象在堆里
2. 方法区(Method Area)—— 类的“档案馆”
- 存放:
- 类的名字、字段、方法定义
- 静态变量(static int count)
- 常量(比如字符串常量 "hello")
- 也是所有线程共享的。
- 在 HotSpot JVM 中:
- JDK 7 及以前:称为“永久代”(PermGen)
- JDK 8+:改为“元空间”(Metaspace),使用本地内存
public class Person {
public static int count = 0; // count 存在方法区
}
3. 虚拟机栈(Java Stack)—— 每个线程的“工作台”
- 每个线程有自己的栈,用来支持方法调用。
- 每调用一个方法,就会创建一个“栈帧”(Stack Frame),压入栈中。
- 栈帧里包含:
- 局部变量表(如 int a = 10;)
- 操作数栈
- 返回地址
特点:
- 方法执行完,栈帧就弹出,资源自动释放。
- 如果递归太深,会抛出 StackOverflowError。
4. 程序计数器(PC Register)—— 线程的“书签”
- 每个线程都有自己的 PC 寄存器。
- 它记录当前线程正在执行的字节码指令的位置。
- 就像你看书时夹的书签,知道看到第几页了。
注意:如果执行的是 native 方法,PC 值为 undefined。
5. 本地方法栈(Native Method Stack)—— 调用非 Java 代码的桥梁
- 当 Java 调用 native 方法(如 Thread.start0())时,使用这个栈。
- 和虚拟机栈类似,但服务的是底层语言(如 C/C++)。