jvm运行时内存划分

java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。

1,程序计数器:是一块较小的内存空间,可以看作是当前线程执行的字节码行号指示器。类似PC。

2,Java虚拟机栈:每个方法执行的时候都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用到执行的过程对应着一个栈帧入栈出栈的过程。

一个线程中的方法调用链可能会很长,很多方法都同时处于执行状态,只有位于栈顶的栈帧才是有效的。称为当前栈帧。与这个栈帧相关联的方法称为当前方法。执行引擎运行所有的字节码指令都只针对当前栈帧进行操作。

局部变量表存放了编译期可知的各种基本数据类型,对象引用,和returnAddress类型。局部变量表所需的内存空间在编译期间完成分配。当进入一个方法时,这个方法需要在帧中分配多大的局部变量空间是完全确定的。在方法运行期间不会改变局部变量表的大小。由于局部变量表简历在线程堆栈上,是线程私有的数据,因此不存在安全问题。在方法的执行时,虚拟机是使用局部变量表完成参数值到参数变量列表的传递过程的,如果执行的是实例方法,那局部变量表中第0位索引的slot默认是用于传递方法所属对象实例的引用。在方法中可以通过关键字this来访问到这个隐含的参数。其余参数则按照参数表顺序排列,占用从1开始的局部变量slot。

操作数栈:也称操作栈,操作数栈的每一个元素可以是任意的Java数据类型,当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是入栈出栈操作,例如算术运算,参数传递都是在操作数栈进行的。

动态链接:每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接,class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用作为参数,这些符号引用一部分会在类加载阶段转化为直接引用,这成为静态解析,另外一部分在每一次运行期间转化为直接引用,这个称为动态链接。

方法返回地址:当一个方法执行后,只有两种方式可以退出这个方法,第一种是return指令,另一种是遇到了异常。异常退出不会给上层调用者返回值,正常退出会给上层返回值,或者void。无论以何种方式退出,在方法退出以后,都需要返回到方法被调用的位置,程序才能继续执行。方法退出的过程实际上就等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中。调整PC计数器的值以指向方法调用指令后面的一条指令等。

3,本地方法栈:与虚拟机栈发挥的作用很相似,本地方法栈为NatiVe方法服务。

4,Java堆:被所有线程共享的一块内存区域,在虚拟机起动时候创建,唯一目的就是存放对象实例。

5,方法区:与堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

6,运行时常量池:方法区的一部分,class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池存放。

7,直接内存,直接内存并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,但是这部分区域也被频繁地使用,而且也可能导致内存溢出。在JDK1.4中新加入了NIO类,引入了一种基于通道与缓冲区的I/O方式,它可以使用NAtive函数库直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能。因为避免了在Java堆和Native堆中来回复制数据。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容