这里写图片描述

##1、PC Register(pc寄存器)

Java虚拟机线程都有自己的pc寄存器。一条Java虚拟机线程只会同时执行一个方法的代码,这个方法称为该线程的当前方法。如果这个方法不是native的,那么pc寄存器就会保存Java虚拟机正在执行的字节码指令的地址,如果这个方法是native的,那pc寄存器的值就是undefined。pc寄存器的容量至少应当能保存一个returnAddress类型的数据或者一个与平台相关的本地指针的值。

##2、Java虚拟机栈

每条Java虚拟机线程都有自己私有的Java虚拟机栈,栈和线程同时创建,用于存储栈帧。栈中存放的为当前线程中的局部基本类型的变量(8种基本数据类型:boolean、char、byte、short、int、long、float、double)、returnAddress、reference。栈以栈帧为单位组成,一个栈帧代表一个方法的调用。栈帧由三部分组成:局部变量区,操作数栈,帧数据区。 ####(1)局部变量区 局部变量区长度由编译期决定,并且存储于类或者接口的二进制表示之中,即通过方法的code属性保存及提供给栈帧使用。 一个局部变量可以保存一个类型为boolean、byte、char、short、int、float、refereace或者returnAddress的数据。两个局部变量可以保存一个类型为long或double的数据。 局部变量使用索引来进行定位访问。首个局部变量的索引值为0。局部变量的索引值是个整数,它大于等于0,且小于局部变量区的长度。

例如:

public static int runClassMethod(int i,long l,float f,double d,Object o,byte b) {   
    return 0;   
} 

public int runInstanceMethod(char c,double d,short s,boolean b) {   
    return 0;   
}

这里写图片描述

runInstanceMethod的局部变量区第一项是个reference(引用),它指定的就是对象本身的引用,也就是我们常用的this,但是在runClassMethod方法中,没这个引用,那是因为runClassMethod是个静态方法。

####(2)操作数栈

每个栈帧内部都包含一个称为操作数栈的后进先出(Last-In-First-Out,LIFO栈)。操作数栈和局部变量区一样,也被组织成一个以字长为单位的数组。但和前者不同的是,它不是通过索引来访问的,而是通过入栈和出栈来访问的。操作数栈是临时数据的存储区域。 例如:

int a= 100;
int b =5;
int c = a+b

这里写图片描述

####(3)帧数据区(动态链接)

每个栈帧内部都包含一个指向当前方法所在类型的运行时常量池的引用,以便对当前方法的代码实现动态链接。在class文件里面,一个方法若要调用其他方法,或者访问成员变量,则需要通过符号引用(symbolic reference)来表示,动态链接的作用就是将这些以符号引用所表示的方法转换为对实际方法的直接引用。类加载的过程中将要解析尚未被解析的符号引用,并且将对变量的访问转换为变量在程度运行时,位于存储结构中的正确偏移量。 由于对其他类中的方法和变量进行了晚期绑定(late binding),所以即便那些类发生变化,也不会影响调用他们的方法。

##3、Java堆

在Java虚拟机中,(heap)是可供各个线程共享的运行时内存区域,也是供所有类实例和数组对象分配内存的区域。Java堆所使用的内存不需要保证是连续的。 Java堆在虚拟机启动的时候就被创建,它存储了被自动内存管理系统(GC垃圾收集器)所管理的各种对象,这些受管理的对象无需也无法显示的销毁。 堆分为Old Space(又名,Tenured Generation)和Young Space。 Old Space主要存放应用程序中生命周期长的存活对象;

Eden(伊甸园)主要存放新生的对象;

S0(from space)和S1(to space)是两个大小相同的内存区域,主要存放每次垃圾回收后Eden存活的对象,作为对象从Eden过渡到Old Space的缓冲地带(S是指英文单词Survivor Space)。

堆之所以要划分区间,是为了方便对象创建和垃圾回收

##4、本地方法栈

Java虚拟机实现可能会使用到传统的栈(通常称为C stack)来支持native方法(指使用Java以外的其他语言编写的方法)的执行,这个栈就是本地方法栈(native method stack)。当Java虚拟机使用其他语言(例如C语言)来实现指令集解释器时,也可以使用本地方法栈。如果Java虚拟机不支持native方法,或者本身不依赖传统栈,那么可以不提供本地方法栈,如果支持本地方法栈,那这个栈一般会在线程创建的时候按线程分配。

##5、方法区

在Java虚拟机中,方法区是可供各个线程共享的运行时内存区域。方法区与传统语言中的编译代码存储区或者操作系统进程的正文段的作用非常类似,它存储了每一个类的结构信息,例如,运行时常量池、字段和方法数据、构造函数和普通方法的字节码内容,还包括一些在类、实例、接口初始化时用到的特殊方法。 方法区在虚拟机启动的时候创建,虽然方法区是堆得逻辑组成部分,但是简单的虚拟机实现可以选择在这个区域不实现垃圾收集和压缩。方法区在实际内存空间中可以是不连续的。

####(1)运行时常量池

运行时常量池是class文件中每一个类或接口的常量池表的运行时表示形式,它包括了若干种不同的常亮,从编译期可知的数值字面量到必须运行期解析后太能获得的方法或字段引用。运行时常量池类似于传统语言中的符号表,不过它存储数据的范围比通常意义上的符号表要更为广泛。 每一个运行时常量池都在Java虚拟机的方法区中分配,在类加载和接口到虚拟机后,就创建对应的运行时常量池。



## 补充(杂乱):

运行时内存也可以分为:共享内存区 和 线程内存区

共享内存区(公用):堆 、方法区 线程内存区:pc寄存器、栈、本地方法栈

栈代表了处理逻辑,堆代表了数据。 堆栈分离才使GC有实现的可能。

String s = new String("Hello World");

s 在栈中,new 的对象在堆中,“”Hello World“”字面量在方法区。