首先,内存模型图,以下:数组
其次,一句话归纳各个区域的做用:布局
1:程序计数器(Program Counter Register),让虚拟机中的字节码解释器经过改变计数器的值来获取下一条代码指令,好比分支、循环、跳转、异常处理、线程恢复等;线程
2:Java 虚拟机栈(Java Virtual Machine Stacks),栈顶存放当前方法,里面有局部变量表,指针
3:本地方法栈(Native Method Stacks),本地方法栈则,是为虚拟机使用到的Native 方法服务,做用同虚拟机栈。对象
4:Java 堆(Java Heap)是Java 虚拟机所管理的内存中最大的一块,是被全部线程共享的一块内存区域。此内存区域的惟一目的就是存放对象实例,几乎全部的对象实例都在这里分配内存。 blog
5:方法区(Method Area)与Java 堆同样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 接口
一:建立一个引用类型对象的内存图 内存
Object obj = new Object(); get
假设这句代码出如今方法体中,那: 编译器
1:首先包含这个方法体的类首先被加载到方法区中;
2:其次方法体自己被压栈进虚拟机栈;
3:“Object obj”这部分的语义将会反映到虚拟机栈的本地变量表中,做为一个reference 类型数据出现。
4:而“new Object()”这部分的语义将会反映到Java 堆中,造成一块存储了Object 类型全部实例数据值(Instance Data,对象中各个实例字段的数据)的结构化内存,这块内存的地址存储在虚拟机栈。另外,在Java 堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法等)的地址信息,这些类型数据则存储在方法区中。
以上过程,用一个更具体的例子,就是建立数组,其内存图以下:
二:建立二位数组的内存图
以下,为了简单起见,省略了方法区的描述:
三:方法调用内存图
假设是这样一段代码,
public class MethodInvoker {
public static void main(String[] args) {
int re = add(1,2);
System.out.println(re);
}private static int add(int i, int j) {
return i + j;
}
}
其内存图是以下的,
准备动做是类和方法的信息加载到方法区,接下来,
1:main方法压栈;
2:方法执行过程当中add方法压栈,而后方法执行,返回3;
3:add方法被弹栈,main方法打印3;
4:main方法弹栈;
三:自定义引用类型对象建立内存图
第一步:
第二步:
附件:关于虚拟机栈访问堆中的数据,有两种方式,以下:
因为reference 类型在Java 虚拟机规范里面只规定了一个指向对象的引用,并无定义这个引用应该经过哪一种方式去定位,以及访问到Java 堆中的对象的具体位置,所以不一样虚拟机实现的对象访问方式会有所不一样,主流的访问方式有两种:使用句柄和直接指针。
若是使用句柄访问方式,Java 堆中将会划分出一块内存来做为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息,以下图所示。
若是使用直接指针访问方式,Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,reference 中直接存储的就是对象地址,以下图所示