自媒体|面试题必问:JVM 运行时数据区详解,写得非常好!

自媒体|面试题必问:JVM 运行时数据区详解,写得非常好!

文章图片

自媒体|面试题必问:JVM 运行时数据区详解,写得非常好!

文章图片

自媒体|面试题必问:JVM 运行时数据区详解,写得非常好!

文章图片





程序计数器(Program Counter Register)

  • 当前线程所执行的字节码行号指示器(逻辑)
  • 通过改变计数器的值来选取下一条需要执行的字节码指令
  • 和线程一对一的关系 , 即“线程私有”
  • 对 Java 方法计数 , 如果是 Native 方法则计数器值为 Undefined
  • 只是计数 , 不会发生内存泄漏
Java 虚拟机栈每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息 。 从方法调用直至执行完成的过程 , 就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程 。



可以通过 -Xss 这个虚拟机参数来指定每个线程的 Java 虚拟机栈内存大小:
java -Xss512M HackTheJava

该区域可能抛出以下异常:
  • 当线程请求的栈深度超过最大值 , 会抛出 StackOverflowError 异常;
  • 栈进行动态扩展时如果无法申请到足够内存 , 会抛出 OutOfMemoryError 异常 。

局部变量表和操作数栈
  • 局部变量表:包含方法执行过程中的所有变量
  • 操作数栈:入栈、出栈、复制、交换、产生消费变量

public class JVMTest {
public static int add(int a int b) {
int c = 0;
c = a + b;
return c;



javap -verbose JVMTest




解读上述指令:
  • stack = 2 说明栈的深度是 2 ;locals = 3 说明有 3 个本地变量 ;args_size = 2 说明该方法需传入 2 个参
  • load 指令表示入操作数栈 , store 表示出操作数栈
执行 add(12) , 说明局部变量表和操作数栈的关系:



本地方法栈本地方法栈与 Java 虚拟机栈类似 , 它们之间的区别只不过是本地方法栈为本地方法服务 。
本地方法一般是用其它语言(C、C++ 或汇编语言等)编写的 , 并且被编译为基于本机硬件和操作系统的程序 , 对待这些方法需要特别处理 。



堆所有对象都在这里分配内存 , 是垃圾收集的主要区域(\"GC 堆\") 。
现代的垃圾收集器基本都是采用分代收集算法 , 其主要的思想是针对不同类型的对象采取不同的垃圾回收算法 。 可以将堆分成两块:
  • 新生代(Young Generation)
  • 老年代(Old Generation)
堆不需要连续内存 , 并且可以动态增加其内存 , 增加失败会抛出 OutOfMemoryError 异常 。
可以通过 -Xms 和 -Xmx 这两个虚拟机参数来指定一个程序的堆内存大小 , 第一个参数设置初始值 , 第二个参数设置最大值 。

java -Xms1M -Xmx2M HackTheJava


Java 内存分配策略
1、静态存储:编译时确定每个数据目标在运行时的存储空间需求
2、栈式存储:数据区需求在编译时未知 , 运行时模块入口前确定
3、堆式存储:编译时或运行时模块入口都无法确定 , 动态分配

问题一:堆和栈的联系
引用对象、数组时 , 栈里定义变量保存堆中目标的首地址 。