本文总结下java虚拟机的第二章的第三小节
欢迎大家关注我的公众号,会不定期更新一些开发与测试的一些技术文章。
1、(原文2.3)HotSpot虚拟机对象探秘
文中以HotSpot虚拟机为例,讲述了java对象的创建以及访问。
当我们写的new关键字被虚拟机执行时:
<1>、检查new所对应的参数是否能在常量池中定位到一个类的符号引用;
<2>、检查这个符号引用代表的类是否已被加载、 解析和初始化过;
<3>、如果没有, 那必须先执行相应的类加载过程(书中第7章);
<4>、上述步骤执行结束后,则为新生对象分配内存,有两种方式:
<1、指针碰撞:指堆内存为规整的,可以简单的分为已被占用的和未被占用的两块,中间以一个指针作为分隔,为新对象分配内存只是将指针向未被占用的内存空间移动下而已;
<2、空闲列表:指堆内存并非规整的,虚拟机维护着一个未使用内存块的列表,当新建对象时,从列表中查找一个可以容下新对象的内存即可;
选择哪种分配方式由使用哪种垃圾收集器决定,Serial、 ParNew等带Compact(标记-整理算法)过程的收集器时, 系统采用的分配算法是指针碰撞,
CMS,基于Mark-Sweep算法(标记-清除算法)的收集器时, 通常采用空闲列表。
注:关于各个垃圾收集器所采用的算法概述如下,后续会详细总结
Serial:复制算法(新生代)
Serial Old:标记-整理算法(老年代)
ParNew:(Serial的多线程版本)复制算法(新生代)
Parallel Scavenge:(“吞吐量优先”收集器)复制算法(新生代)
Parallel Old:(Parallel Scavenge的老年代版本)标记-整理算法 (老年 代)
CMS和G1后续会详细总结。
继续对象的创建内容总结...
<5>、解决对象创建在多线程情况下的线程安全问题的两种方案:
<1、CAS配上失败重试的方式保证更新操作的原子性;
<2、把内存分配的动作按照线程划分在不同的空间之中进行, 即每个线程在Java堆中预先分配一小块内存, 称为本地线程分配缓冲( Thread Local Allocation Buffer,TLAB) 。 哪个线程要分配内存, 就在哪个线程的TLAB上分配, 只有TLAB用完并分配新的TLAB时, 才需要同步锁定;
虚拟机通过-XX: +/-UseTLAB参数设定使用TLAB。
<6>、初始化默认值;
<7>、对对象进行必要的设置, 例如这个对象是哪个类的实例、 如何才能找到类的元数据信息、 对象的哈希码、 对象的GC分代年龄等信息;
2、(原文2.3.2)在HotSpot虚拟机中, 对象在内存中的布局分为3块区域: 对象头( Header) 、实例数据( Instance Data) 和对齐填充( Padding) 。此部分都是些硬知识,且不常见,故暂时未总结,感兴趣的读者可以阅读原书。
3、(原文2.3.3) 对象的访问定位
主流的访问方式有使用句柄和直接指针两种。
<1>使用句柄:此种情况Java堆中会分出一块内存作为句柄池, 引用中存储的就是对象的句柄地址, 而句柄中包含了对象实例数据与类型数据各自的具体地址信息,好处是句柄地址稳定,频繁的垃圾收集下只改实例数据指针,而引用本身不变。
<2>直接指针:看图我就不说话了
好处是速度更快, 节省了一次指针定位的时间开销,且因对象访问在Java中超级频繁, 所以会节省一大笔时间;
HotSpot是使用直接指针来访问对象的。
本节完。
本文暂时总结了java虚拟机(第二版)中的2.3节的主要知识点,和一些up主自己的知识点,如果有记忆差错,还望见谅,后面我会找时间继续的,最后,我总结的知识点比较简练,如果需要了解详细内容的话,请阅读原书。
欢迎大家关注我的公众号,会不定期更新一些开发与测试的一些技术文章。