主要内容
- JVM运行时数据区
- 线程安全逻辑图
一.JVM运行时数
Java虚拟机在执行java程序的过程中会把它管理的内存划分为若干个不同的数据区域
如图1.1:
1) 程序计数器:指向当前线程正在执行的字节码的地址或行号;
如果执行的是Native方法,计数器的值为空(Undefined)
个人理解图:程序计数器记录当前线程的地址,当A线程cup资源被抢着后再次执行
A线程,可以快速找到A线程。
2) java虚拟机栈:存储当前线程运行方法所需的数据、指令、返回地址;
Java虚拟机栈描述的是Java方法执行的内存模型:每个方法被调用的时候都会创建一个栈帧,用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机中从入栈到出栈的过程。
虚拟机栈异常情况:
(1)如果线程请求的栈深度太深,超出了虚拟机所允许的深度,就会出现StackOverFlowError。
(2)虚拟机栈可以动态扩展,如果扩展到无法申请足够的内存空间,会出现OutOfMemoryError。
- 局部变量表:保存编译器可知道的基本数据类型、对象一引用(指向堆中)
(1)局部变量表单位(Slot)32位,62位长度的double和long会占用2个空间。
- 操作数栈:进行压栈和出栈把局部变量的值放到局部变量表的相应位置。
- 动态链接:对应运行时常量池存放类的加载等信息。
- 方法出口:结束方法或抛出异常等。
内部结构如图:1.2
案例:
如果由两个局部变量:int i=10;int b =20;(根据先后顺序对应在局部变量表中的位置)
首先: 把int类型的10压入操作数栈,
第二步:出栈把 int类型的值存入局部变量表1对应的位置 ,b同理;
当进行 int c =i+b时 把int类型的10和20 压栈计算在复制给c对应的位置。
局部变量表中对象引用访问方式如下图:
3) 本地方法栈:用来执行native方法的(比如C或C++) ;
4) 方法区:用于存储已经被虚拟机加载的类信息(即加载类时需要加载的信息,包括版本、field、方法、接口等信息)、final常量、静态变量、JIT编译器即时编译的代码;
- 运行时常量池:用于存储编译期就生成的字面常量、符号引用、翻译出来的直接引用;
方法区异常情况:OutOfMemoryError:PermGenspace异常:
(1)在方法区上进行垃圾收集,条件苛刻而且相当困难 定义了异常内存不足时抛出;
5) 堆:存储对象实例(主要进行GC的区域)
异常情况: OutOfMemoryError:Javaheap space异常:
(1)在执行垃圾回收之后(Full GC),仍没有足够的内存分配,也不能再扩展将会抛出异常;
二.线程安全逻辑图:
如图2.1可知程序计数器、虚拟机栈、本地方法栈都是线程安全的、方法去和堆是线程共享的。
参考:《深入理解java虚拟机》第二版