【深入理解Java虚拟机】内存管理和对象访问

一:JVM内存区域划分

【深入理解Java虚拟机】内存管理和对象访问
(1)程序计数器(线程私有):类似于eclipse中断点程序(行号指示器),记录了程序下一步需要执行的字节码指令,分支,循环等分支。线程私有,每个线程有一个程序计数器
程序计数器是为了多线程情况下,线程执行切换后,处理器回来原来线程能找到之前线程执行的位置
若执行Java方法,计数器记录是是正在执行的虚拟机字节码指令的地址,
若执行Native方法,这个计数器为空,此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
(2)java虚拟机栈(栈内存,线程私有):执行java方法,生命周期与线程相同,每个方法在执行时会创建一个栈帧(Stack Frame)用于存储局部变量表,操作数栈,动态链接,方法出口等信息。
局部变量表存放:各种基本数据类型,对象应用,returnAddress类型。
其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot),其余的数据类型只占用1个。局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在帧中分配多大的局部变量的空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
(3)本地方法栈:允许的是 native 关键字标识的方法,可有虚拟机*实现。
(4)堆内存(所有线程共享):虚拟机启动时创建,存放对象实例和数组。随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配,标量替换优化技术将会导致一些微妙变化,所有的对象都分配在堆上也逐渐变得不是那么“绝对”了。 堆是垃圾回收的主要区域,堆会根据不同的垃圾回收机制进行划分。
(5)方法区(所有线程共享):存储已被虚拟机加载的类信息,常量,静态变量,JIT编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Noe-Heap(非堆),目的是与Java堆区分开来
运行时常量池是方法区的一部分。Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分将在类加载后进入方法区运行时常量池中存放。一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。String类的intern()方法也可以放入运行时常量池中。

二:对象的创建过程

对象的创建过程:
1、虚拟机遇到new指令,首先将去检查这个指令的参数是否在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载,解析和初始化过,若没有,则先进行类加载过程
2、虚拟机为新生对象分配内存,内存大小通过类加载完成后可以完全确定
内存分配方式可以分为:指针碰撞,空闲列表 两种方式
分配内存可能存在并发问题,解决方案:
1)采用同步原理,通过CAS更新保证原子性
2)把内存分配的操作按照线程划分不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB),哪个线程分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并分配新的TLAB时,才需要同步锁定。
通过 -XX: +/-UseTLAB参数类设定虚拟机是否使用此方式分配内存
3、默认初始化,虚拟机先将分配到的内存空间都初始化为零值(不包括对象头),如果使用TLAB,这步会提前到TLAB分配时进行
4、配置信息,如这个对象属于哪个类的实例,如何才能找到类的元数据信息,对象的哈希码,对象的GC分代年龄等信息,这些信息存放在对象头中
5、执行方法,对对象进行初始化

三:HotSpot对象内存布局

对象头Header 实例数据(Instatnce Data) 对其填充(Padding)
Mark Word 和 类型指针(执行它的类元数据的指针) 真正存储的对象的内容 非必然存在,仅仅是占位符

Mark Word 存放的是:对象哈希码,对象分代年龄,指向锁记录的指针,线程持有锁,偏向线程ID,偏向时间戳

类型指针(执行它的类元数据的指针),虚拟机用这个指针来确定这个对象是哪个类的实例

四:对象的访问定位

访问对象采用两种方式:
1、句柄
使用句柄访问方式,java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
优点:稳定,对象被移动(垃圾收集)时,只会改变句柄中实例数据的指针,而reference本身不需要修改。
【深入理解Java虚拟机】内存管理和对象访问
2、直接指针
使用直接指针方式,那么堆对象的布局中必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址
优点:速度快
【深入理解Java虚拟机】内存管理和对象访问
HotSpot虚拟机采用直接指针的方式访问对象