注:如其中有不懂的名词,下面有名词解释
1、对象的创建(限于普通Java对象,不包括数组和Class对象等)
(1)检查这个指令的参数能否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否被加载,解析,初始化,如果没有,先加载
(2)为新生对象在java堆中分配内存,java堆如果规整,分配内存的方法可使用“指针碰撞“,如果不规整,则使用”空闲列表“。选择哪种分配方式是根据这个虚拟机所采用的垃圾收集器是否带有压缩整理功能决定的。例如,在使Serial、 ParNew等带Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。
(3)内存分配完之后,虚拟机需要将分配到的内存空间都初始化为零值。如果用TLAB,则在TLAB分配时进行。
(4)虚拟机对对象进行必要的设置,例如这个对象是哪个类的实例、 如何才能找到类的元数据信息、 对象的哈希码、 对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header)之中。
(5)执行init方法,即按照程序员的意愿进行初始化。
注意事项:
对象创建在并发情况下不是线程安全的,解决办法:
(1)同步
(2)在对象创建时,把内存分配的动作按照线程划分在不同的空间中进行,即每个线程在java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer TLAB),哪个线程要分配内存,在哪个线程的TLAB上分配,只有TLAB用完分配新的TLAB时,才需要同步锁定。
注:虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定
2、在HotSpot虚拟机中,对象的内存中存储的布局可分为3块:对象头、实例数据、对齐填充
(1)对象头的数据长度在32位和64位的虚拟机上分别对应32bit和64bit。
(2)虚拟机中的分配策略:相同宽度的字段总是被分到一起。
3、对象的访问定位
HotSpot使用的是直接指针访问
图1句柄池访问对象
图2直接指针访问对象
直接指针访问要比句柄访问快一些,因为减少了一次指针定位的时间开销。
指针碰撞:
假设Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump the Pointer)。
空闲列表:
如果Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)
符号引用:
符号引用是一个字符串,它给出了被引用的内容的名字并且可能会包含一些其他关于这个被引用项的信息——这些信息必须足以唯一的识别一个类、字段、方法。这样,对于其他类的符号引用必须给出类的全名。对于其他类的字段,必须给出类名、字段名以及字段描述符。对于其他类的方法的引用必须给出类名、方法名以及方法的描述符。
---
什么是HotSpot VM & 深入理解Java虚拟机 JVM
========================
提起HotSpot VM,相信所有Java程序员都知道,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。
但不一定所有人都知道的是,这个目前看起来“血统纯正”的虚拟机在最初并非由Sun公司开发,而是由一家名为“Longview Technologies”的小公司设计的;
甚至这个虚拟机最初并非是为Java语言而开发的,它来源于Strongtalk VM,
而这款虚拟机中相当多的技术又是来源于一款支持Self语言实现“达到C语言50%以上的执行效率”的目标而设计的虚拟机,
Sun公司注意到了这款虚拟机在JIT编译上有许多优秀的理念和实际效果,在1997年收购了Longview Technologies公司,从而获得了HotSpot VM。
HotSpot VM既继承了Sun之前两款商用虚拟机的优点(如前面提到的准确式内存管理),也有许多自己新的技术优势,
如它名称中的HotSpot指的就是它的热点代码探测技术(其实两个VM基本上是同时期的独立产品,HotSpot还稍早一些,HotSpot一开始就是准确式GC,
而Exact VM之中也有与HotSpot几乎一样的热点探测。
为了Exact VM和HotSpot VM哪个成为Sun主要支持的VM产品,在Sun公司内部还有过争论,HotSpot打败Exact并不能算技术上的胜利),
HotSpot VM的热点代码探测能力可以通过执行计数器找出最具有编译价值的代码,然后通知JIT编译器以方法为单位进行编译。
如果一个方法被频繁调用,或方法中有效循环次数很多,将会分别触发标准编译和OSR(栈上替换)编译动作。
通过编译器与解释器恰当地协同工作,可以在最优化的程序响应时间与最佳执行性能中取得平衡,而且无须等待本地代码输出才能执行程序,
即时编译的时间压力也相对减小,这样有助于引入更多的代码优化技术,输出质量更高的本地代码。
在2006年的JavaOne大会上,Sun公司宣布最终会把Java开源,并在随后的一年,陆续将JDK的各个部分(其中当然也包括了HotSpot VM)在GPL协议下公开了源码,
并在此基础上建立了OpenJDK。这样,HotSpot VM便成为了Sun JDK和OpenJDK两个实现极度接近的JDK项目的共同虚拟机。
在2008年和2009年,Oracle公司分别收购了BEA公司和Sun公司,这样Oracle就同时拥有了两款优秀的Java虚拟机:JRockit VM和HotSpot VM。
Oracle公司宣布在不久的将来(大约应在发布JDK 8的时候)会完成这两款虚拟机的整合工作,使之优势互补。
整合的方式大致上是在HotSpot的基础上,移植JRockit的优秀特性,譬如使用JRockit的垃圾回收器与MissionControl服务,
使用HotSpot的JIT编译器与混合的运行时系统。