深入JVM内核(一)JVM内存区域与运行机制

JVM启动流程

JVM启动流程

JVM基本结构

JVM基本结构

程序计数器

  • 每个线程拥有一个PC寄存器
  • 在线程创建时创建
  • 指向下一条指令的地址
  • 执行本地方法师,PC的值为undefined

方法区

  • 所有线程共享
  • 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

Java堆

  • 所有线程共享
  • 和程序开发密切相关
  • 几乎所有的对象实例都在这里分配内存
  • 对分代GC来说,堆也是分代的
  • GC的主要工作区间

Java虚拟机栈

  • 线程私有
  • 生命周期与线程相同
  • 栈由一系列帧组成(因此Java栈也叫做栈帧)
  • 帧用于存储局部变量、操作数栈、动态链接、方法出口等信息
  • 方法从调用到执行完成的过程,就对应一个栈帧在虚拟机栈中入栈到出栈的过程
  • 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常

本地方法栈

  • Java虚拟机栈发挥的作用相似
  • 区别在于:
    • 虚拟机栈为虚拟机执行Java方法(也就是字节码)服务
    • 本地方法栈为虚拟机使用到的Native方法服务

堆、栈、方法区的交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class AppMain { 
//运行时, jvm 把appmain的信息都放入方法区
public static void main(String[] args) {
//main 方法本身放入方法区。
Sample test1 = new Sample( " 测试1 " );
//test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
Sample test2 = new Sample( " 测试2 " );
test1.printName();
test2.printName();
}

public class Sample {
//运行时, jvm 把appmain的信息都放入方法区
private name;
//new Sample实例后, name 引用放入栈区里, name 对象放入堆里
public Sample(String name) {
this .name = name;
}
//print方法本身放入 方法区里。
public void printName() {
System.out.println(name);
}
}

JVM内存模型

内存模型

  • 每一个线程有一个工作内存和主存独立
  • 工作内存存放主存中变量的值的拷贝

  • 当数据从主内存复制到工作存储时,必须出现两个动作:第一,由主内存执行的读(read)操作;第二,由工作内存执行的相应的load操作;当数据从工作内存拷贝到主内存时,也出现两个操作:第一个,由工作内存执行的存储(store)操作;第二,由主内存执行的相应的写(write)操作.
  • 每一个操作都是原子的,即执行期间不会被中断
  • 对于普通变量,一个线程中更新的值,不能马上反应在其他线程中
    如果需要在其他线程中立即可见,需要使用 volatile 关键字

内存模型


参考:

  • 周志明. 深入理解JVM虚拟机