JVM内存分配笔记

一、JVM运行过程

1)编写.java文件
2)JVM(虚拟机)将.java文件编译成.class文件
3)类加载器加载.class文件
4)加载完毕,交由JVM执行引擎(Execution Engine)和字节码解释器执行
在执行过程中,JVM会用一部分空间来存储程序执行期间需要用到的数据和相关信息。
这一段空间分为Runtime Data Area(运行时数据区),也就是我们常说的JVM内存。

二、Runtime Data Area(运行时数据区)包含那几个部分?

根据《Java虚拟机规范(Java SE 7版)》 的规定,通常包括以下几个部分:
1)程序计数器(Program Counter Register)----线程私有
2)JVM栈(JVM Stack)----线程私有
3)本地方法栈(Native Method Stack)----线程私有
4)堆(Heap)----线程共享
5)方法区(Method Area)----线程共享

三、运行时数据区的每部分到底存储了哪些数据?

1)程序计数器(Program Counter Register)----线程私有
一块较小的内存空间,可以当做是当前线程所执行的字节码文件的行号指示器,用来指示执行哪一条指令。
JVM多线程是通过获取CPU时间片的方式运行的,确保每次线程中断都能回到原来的位置,各个线程之间的计数器互不影响。
如果线程正在执行的是一个非Native方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。
字节码解释器的工作就是通过改变这个计数器的值,来选取下一条需要执行的字节码的指令,分支、 循环、 跳转、 异常处理、 线程恢复等基础功能都需要依赖这个计数器来完成。

2)JVM栈(JVM Stack)----线程私有
JVM栈是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧,用于存储:
a.局部变量表:用来存储方法中的局部变量,包括方法中声明的非静态变量以及函数形参。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。
局部变量表的大小在编译器就可以确定其大小了,因此在程序执行期间局部变量表的大小是不会改变的。也就是在编译成.class文件就已经确定了局部变量的内存。
b.操作数栈:数据结构中,常用操作数栈对表达式进行求值,因此,程序中的所有计算过程都是在借助于操作数栈来完成的。
c.方法出口:当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。
d.指向运行时常量的引用:方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。
e.等信息

3)本地方法栈(Native Method Stack)----线程私有
本地方法栈和虚拟机栈所发挥的作用是非常相似的。
两者区别:虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。 
甚至有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

4)堆(Heap)----线程共享
Java虚拟机所管理的内存中最大的一块。
此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。 

5)方法区(Method Area)----线程共享
在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
运行时常量池(Runtime Constant Pool)是方法区的一部分。 它是每一个类或接口的常量池的运行时表示形式,
在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。当然并非Class文件常量池中的内容才能进入运行时常量池,
在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。

猜你喜欢

转载自blog.csdn.net/qq_35341771/article/details/81778733
今日推荐