Understanding the JVM Reading Notes 1

《深入理解Java虚拟机》读书笔记(1)第二章Java内存区域与内存溢出异常

2.2 远行时数据区域

远行时数据区的主要构成:程序计数器,Java虚拟机栈,本地方法栈,Java堆,方法区。
1.程序计数器(PC):字节码解释器工作时通过改变计数器的值来选取下一条需要执行的字节码指令。为线程私有,每个线程都有自己独立的PC。唯一的没有在Java虚拟机规范里规定OOM情况的区域。
执Java方法放的是正在执行的虚拟机字节码指令的地址,执行Native方法则内容为空。
2.Java虚拟机栈:线程私有,生命周期与线程相同。描述Java方法执行的内存模型:用栈帧来存储局部变量表,操作数栈,动态链接,方法出口等信息。方法执行的过程等同于栈帧在虚拟机栈中的入栈出栈过程。
局部变量表存放了编译期可知的基本数据类型,对象引用和returnAddress类型,单位为slot,long和double占用2个slot。局部变量表在编译时完成分配,并且不会在远行时改变。
Java虚拟机栈可能产生SOE异常和OOM异常。
3.本地方法栈:为Native方法服务,线程私有,可能产生SOE异常和OOM异常。
4.Java堆:唯一目的就是存放对象实例,线程共享,是GC的主要管理区域。采用不连续分区,逻辑上连续。可扩展,会产生OOM异常。
5.方法区:也称为非堆(Non-Heap),线程共享。存储的是已经被虚拟机加载的类信息,常量,静态变量,JIT编译后的代码等数据。GC主要针对常量池的回收和类型的卸载。在HotSpot用永久代实现方法区,方法区约等于永久代。也会产生OOM异常。
6.远行时常量池:属于方法区。Class文件中的常量池信息在类加载后存放在这里,直接引用也存放在这里,(Class文件的常量池信息存放的是符号应用)。具有动态性,可在远行期间加入新的常量,比如String的intern()方法。也会产生OOM异常。
7.直接内存:使用Native函数分配的堆外内存。大小受机器内存制约。和NIO类IO操作方式有关。也会产生OOM异常。

2.3 HotSpot虚拟机对象

1.对象的创建
当虚拟机遇到new指令时依次发生了以下事情:
* 类加载检查:检查指令的参数能否定位到某个类的符号引用,检查符号引用指向的类是否已被加载,解析和初始化过,若干没有则要先执行类加载过程
* 分配内存:类加载完成后可确定需要的内存大小,根据Java堆在GC后的规整(即空间分区是否全部连续)程度分为“指针碰撞”和“空闲列表”两种分配方式,Java堆规整采用“指针碰撞”,只需要移动指针即可,对应有Compact(整理)过程的GC。Java堆不规整采用“空闲列表”,对应采用Mark-Sweep算法的GC。
多线程下的分配:对内存分配的动作进行同步和先分配TLAB,分配完TLAB之后在进行同步。
(TLAB:本地线程分配缓冲,每个线程预先在堆中分配一块,线程先在自己的TLAB上分配内存,-XX:+/UseTLAB参数设定)
* 初始化为零值:所有对象设为零值,即默认值。
* 设置对象头(Object Header)
* 执行方法:给对象赋程序猿给的初始值。

2.对象的内存布局:对象头,实例数据,对齐填充。
* 对象头
由对象自身的远行时数据和类型指针两部分组成。
对象自身的远行时数据:32位机器为32bit,64位机器为64bit,称为“Mark Word”。非固定的数据结构和会复用自己的存储空间。32位机器下对象未被锁定时25bit存储对象哈希码,4bit存储对象分代年龄,2bit存储锁标志位,1bit固定为0。其他状态下存储内容29bit和2bit的锁状态位会发生变化。
类型指针:对象指向自己的类元数据的指针,虚拟机可以通过这个指针确定这个对象是哪个类的实例。如果是Java数组,对象头中还需要一块用于记录数组长度的数据。类型指针和虚拟机实现有关,如果采用句柄池的访问方式则不需要保留类型指针,由句柄池保存指向对象类型数据的指针。(句柄池见2.3.3)
* 实例数据:对象真正存储的有效信息,即代码中定义的字段内容。包括继承的和在子类中定义的。相同宽度(shorts/chars,longs/doubles等)的字段总是分配在一起,满足前述条件下父类中定义的变量出现在子类之前。CompactFields参数值为true(默认为true)时子类中较窄的变量可能会插入到父类变量的空隙之中。
* 对齐填充:占位符HotSpotVM要求对象其实地址为8字节的整数倍,对象头大小为8字节的倍数(32或64位)。

3.对象的访问定位
程序通过栈上的reference数据(见局部变量表)操作堆上的具体对象,访问堆中对象的具体方式由虚拟机决定。方式有以下两种:
* 句柄:在堆中划出一部分内存作句柄池,reference中存储对象的句柄地址,句柄中包含了对象实例数据(堆中)和对象类型数据(方法区中)的地址。优势在于句柄地址稳定,对象移动只改变句柄中的实例数据指针,reference本身不需要改变。
* 直接指针:reference中存储的直接是对象地址。reference指向对象实例数据,对象实例数据中再存放指向对象类型数据的指针指向对象类型数据。优势一句话就是快!,节省了一次指针定位的开销(句柄池实现中reference要先指向句柄池)。
HotSpot采用了直接指针的方式访问对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值