Java运行时数据区域
一.程序计数器
它可以看作是当前线程执行的字节码的行号指示器,是线程私有的内存。
如果当前执行的是Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址。
如果当前执行的是Native方法,那么这个计数器的值为空。
二.虚拟机栈
也是线程私有的,其中描述的是Java方法执行的内存模型。每个方法在执行时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出入口等信息。每一个方法从调用到直到执行完毕的过程,就是一个栈帧在虚拟机栈中的入栈和出出栈。
三.本地方法栈
与Java虚拟机栈的作用类似,不同的是Java虚拟机栈是为字节码服务,而本地方法栈是为本地方法服务(Native Method)
四.Java堆
在笔记一种有详细介绍
五.方法区
与Java堆一样,是各个内存共享的一片内存区域。用于存储被虚拟机加载的类信息,常量,静态变量,即时编译后的一些代码等数据。与Java堆区分开来,又叫做非堆。这一部分又可以叫“永久代”,Java虚拟机规范中可以不对该区域进行GC。因为要是GC的话,这一部分的回收率特别低。
六.运行时常量池
方法区的一部分,用于存储编译器生成的各种字面量和符号引用,这部分将在类加载后进入方法区的常量池
字面量:int i = 1; 整数1就是i的字面量,String str = “abc”; “abc”就是str的字面量。
七.直接内存
不是Java虚拟机规范定义的区域,但是这一部分经常被使用。
Java对象
一.对象的创建
我们都知道Java是通过new关键字来创建对象的,那么当一个new指令被执行时,JVM到底做了那些事情呢?
1.当虚拟机要一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号的引用,并且检查这个类是否已经被加载,解析和初始化。如果没有,那么先将执行相应的类加载的过程。
2.在类加载检查通过后,接下来虚拟机将为新生对象分配空间。对象所需的大小在类加载完成之后就可以确定。当Java堆规整时,JVM会把所有用过的内存放到一边,空闲的放到另外一边,然后中间用一个指针隔开。当Java堆不规整时,JVM必须维护一个“空闲列表”,记录那些内存是可用的,那些内存是不可用的
3.在内存分配完成以后,虚拟机将分配到的空间都初始化为零值。接下来,虚拟机将会对对象头做必要的设置。在工作都完成之后,在虚拟机的角度来看,一个新的对象便是产生了,但是从Java程序来看,才刚刚开始,因为还没有执行<init>方法,执行new指令之后便是会执行<init>方法,这样一个真正的对象才算完全生产出来
二.对象的内存布局
对象在内存中存储的布局可以分为三个部分:对象头,实例数据,对头填充
对象头中存储的是对象自身运行的数据:如HashCode,GC分代年龄,锁标志状态,线程持有的锁,偏向线程ID,偏向时间戳。