深入理解Java虚拟机(一)——虚拟机运行时数据区域

xiaoxiao2021-02-28  35

Java虚拟机在执行Java程序时会将所管理的内存区域分为几个部分(数据区域),分别是程序计数器(Program Counter Register),Java虚拟机栈(VM Stack),本地方法栈(Native Method Stack),Java堆(Heap),方法区(Method Area)

程序计数器(Program Counter Register)

程序计数器,一块较小的内存空间,可以看成是当前线程所执行的字节码的行号指示器,在虚拟机的概念模型里(不一定是具体实现),字节码解释器通过改变程序计数器的值来选取下一条需要执行的字节码指令,来实现分支,循环,跳转,异常处理,线程恢复等基础功能

Java虚拟机的多线程是通过线程的轮流切换来实现的,因此为了线程切换后能恢复到正确的执行位置,每条线程应该有一个独立的程序计数器,保证线程之间互不影响,独立存储,这些区域成为“线程私有”的内存

如果线程正在执行一个java方法,计数器记录的就是正在执行的字节码的地址(或者可能是相对于方法开头的地址偏移量),如果执行的是一个native方法,因为native方法的方法体不是由java字节码构成,所以jvm规范规定此时计数器为空(Undefined)

Java虚拟机栈(Java Virtual Machine Stacks)

和程序计数器一样,Java虚拟机栈也是线程私有的,描述的是Java方法执行时的内存模型:每个java方法执行时会同事创建一个栈帧(Stack Frame),用于存储局部变量表,操作数栈,动态链接,方法出口等信息

方法的调用到执行完成,就对应这一个栈帧在虚拟机栈从入栈到出栈的过程

局部变量表存放了各种基本数据类型(boolean byte char short int float long double),对象引用(reference类型,可以是指向对象起始位置的指针,可是是指向一个代表对象的句柄或其他与对象有关的位置)和returnAddress类型(指向一条字节码的地址)

long和double类型占用2个局部变量空间(Slot),其他占1个,局部变量表的内存空间在编译时完成分配,方法执行时无法改变

本地方法栈(Native Method Stacks)

本地方法栈和虚拟机栈类似,不同的是本地方法栈执行的是native方法,而虚拟机栈执行的是java方法,JVM规范中对本地方法栈没有强制规定,因此不同虚拟机可以有不同实现方式

Java堆(Java Heap)

Java堆是虚拟机管理内存中最大的一块,是所有线程共享的一块内存,在虚拟机启动时创建,用于存放对象实例,绝大多数对象实例以及数组都要在堆上分配内存(由于技术的发展包括逃逸分析,栈上分配,标量替换,使得某些对象不一定在堆上分配)

Java堆也是垃圾收集器管理的主要区域,垃圾堆o(╯□╰)o(Garbage Collected Heap) 从垃圾回收的角度(分代收集算法)看,Java堆可细分为 新生代和老年代;Eden空间 From Survivor空间 To Survivor空间等 从内存分配的角度看,Java堆可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer)

方法区(Method Area)

方法区也是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等,垃圾收集行为在这个区域较少出现,主要是针对常量池的回收和类型的卸载,条件较为苛刻

运行时常量池(Runtime Constant Pool)是方法区的一部分,Class文件除了有类的版本,字段,方法,接口等信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分在类加载后存放到方法区的运行时常量池里

分类:

线程私有:程序计数器,虚拟机栈,本地方法栈线程共享:Java堆,方法区
转载请注明原文地址: https://www.6miu.com/read-2632508.html

最新回复(0)