1.背景与大纲

  在我们了解了java虚拟机的运行时数据区后,我们大概知道了虚拟机内存的概况,但是我们还是不清楚具体怎么存放的访问的;

  接下来,我们将深入探讨HotSport虚拟机在java堆中对象的分配、布局、访问的全过程。

2.对象创建

  

  1.类加载:当遇到new指令时,先判断这个类是否被加载、解析、初始化过,如果没有,先执行相应类的加载过程(后面会详细分析这个过程)。

  2.分配内存:

  如果Java堆内存是规整连续的,采用“指针碰撞”的分配方式,

  

  如果是不连续规整的,采用“空闲列表”分配方式。如下图:灰色表示已使用,数字表示可用

  

  内存是否规整取决于垃圾收集器是否带有压缩整理功能。

  Serial,ParNew等带有Compact过程的收集器,采用的分配算法是“指针碰撞”。

  而CMS这种基于Mark-Sweep算法的收集器,通常采用“空闲列表”分配方式。

  线程安全问题:即便是修改指针指向位置,A\B两个线程有可能会指向同一个地址

  

  解决方案:
  a.同步锁:
  b.TLAB:本地线程分配缓冲,把内存的分配动作按照线程划分在不同的空间进行
  等TLAB用完分配新的TLAB时,才需要同步锁
  虚拟机是否使用TLAB,可以通过-XX:+/UseTLAB参数设定

  

  .对象初始化为零对象:

  a.如果使用的是TLAB,这一步可以提前到TLAB分配的时候进行
  b.作用:保证了实例字段在java代码中可以不赋初始值就可以直接使用

  .对象头进行设置,
  包括这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。

  5.java程序初始化,最后执行init方法,把对象按照程序员的意愿进行初始化。这样一个真正可用的对象才算完全生产出来。

3.对象内存布局  

  

  对象内存布局分为三块区域

3.1.对象头(Header)

  对象头主要包括:运行时数据、类型指针

3.1.1.运行时数据

  对象头,存储对象自身的运行时数据,如哈希码、对象的GC分代年龄、锁状态标志、偏向线程ID、偏向时间戳,
  1.这部分数据的长度在32位和64位虚拟机中,分别为32bit和64bit。
  2.官方称其为:Mark Word
  3.存储的运行时数据过多(超出32bit、64bit)
  4.Mark Word被设计成为一个非固定数据结构,以便在极小的空间内存存储尽量多的信息

  

  5.根据对象的状态复用自己的存储空间

3.1.2.类型指针

  另一个部分是类型指针
  1.定义:对象指向它的类元数据的指针
  2.作用:虚拟机通过这个指针来确定这个对象是哪个类的实例
  3.但是:并不是所有的虚拟机实现都必须在对象上保留类型指针
  4.结论:查找对象的元数据信息并不一定要经过对象本身(下一节详细讲)

3.1.3.特例

  另外,如果对象是java数组
  1.对象头必须有一块用于记录数组长度的数据
  2.原因:普通java对象的元数据信息可以确定java对象的大小
  3.但是,从数组的元数据中却无法确定数组的大小

3.2.实例数据(Instance Data)

  1.存储内容:是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容
  2.存储范围:无论是父类还是子类都要记录
  3.存储顺序:存储顺序会受到虚拟机分配策略参数(fieldsAllocationStyle)和字段定义顺序的影响
  4.默认分配策略顺序:按字节由大到小(即由宽到窄),
  longs/doubles->ints->shorts/chars->bytes/booleans->oops(Ordinary Object Pointers)普通对象指针
  5.在满足分配策略这个前提条件下,父类中定义的变量会出现在子类之前
  6.如果CompactFields参数值为true,那么子类中较窄的变量也可能会插入到父类变量的空隙之中

3.3.对齐补充(Padding)

  1.作用:对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。
  2.原因:由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。
  3.解决:而对象头部分正好是8字节的倍数(1倍或者2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。

4.对象的访问定位

  

  对象的访问定位
  1.Java程序需要通过栈上的reference数据来操作堆上的具体对象。
  2.由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用,
  3.并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,
  4.所以对象访问方式也是取决于虚拟机实现而定的。
  5.目前主流的访问方式有使用句柄和直接指针两种。
  6.总结:通过reference数据来定位具体对象,但reference只规定了对象的引用,并没有提供具体实现

  

4.1.句柄方式

  1.Java堆中将会划分出一块内存来作为句柄池,
  2.reference中存储的就是对象的句柄地址,
  3.而句柄中包含了对象实例数据与类型数据各自的具体地址信息。

  优点:
  使用句柄来访问的最大好处就是reference中存储的是稳定的句柄地址,

  在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。

4.2.直接指针方式

  1.Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,
  2.而reference中存储的直接就是对象地址。

  优点:
  使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,

  由于对象的访问在Java中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。

4.3.案例

  虚拟机Sun HotSpot 使用的是直接指针的方式!

深入理解JVM-hotspot虚拟机对象探秘的更多相关文章

  1. 深入理解JVM(③)——之HotSpot虚拟机对象探秘

    前言 上篇文章介绍了Java虚拟机的运行时数据区域,大致明白了Java虚拟机内存模型的概况,下面就基于实用优先的原则,以最常用的虚拟机HotSpot和最常用的内存区域Java堆为例,升入探讨一下Hot ...

  2. 深入理解JVM:HotSpot虚拟机对象探秘

    对象的创建 java是一门面向对象的语言.在Java程序执行过程中无时无刻有Java对象被创建出来.在语言层面上,创建对象(克隆.反序列化)一般是一个newkeyword而已,而在虚拟机中,对象的创建 ...

  3. JVM探究之 —— HotSpot虚拟机对象探秘

    本节以常用的虚拟机HotSpot和常用的内存区域Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配.布局和访问的全过程. 1. 对象的创建 Java是一门面向对象的编程语言.在语言层面 ...

  4. 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.2.HotSpot虚拟机对象探秘

    对象的创建过程 1.加载类 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载. 解析和初始化过. 如果没有,那必须 ...

  5. 《深入理解java虚拟机》笔记(2)HotSpot虚拟机对象探秘

    一.对象的创建 1.类加载: 虚拟机在遇到一条new指令时候,检查类是否已被加载.解析.初始化过,如果没有,则执行类加载过程. 2.分配内存:类加载完成后,则为新对象从java堆上分配内存,分配内存有 ...

  6. JVM学习十三 - (复习)HotSpot 虚拟机对象探秘

    对象的内存布局 在 HotSpot 虚拟机中,对象的内存布局分为以下 3 块区域: 对象头(Header) 实例数据(Instance Data) 对齐填充(Padding) 对象头 对象头记录了对象 ...

  7. 深入理解Java虚拟机-HotSpot虚拟机对象探秘

    一.对象的创建过程 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那就先执行相应的类 ...

  8. HotSpot虚拟机对象探秘-笔记

    学习目的:探讨HotSpot虚拟机在Java堆中对象分配.布局和访问的全过程. 1.对象的创建 虚拟机在执行到一条new指令时,先要检查指令的参数(将要实例化的类)是否已经被加载.解析.初始化过,如果 ...

  9. HotSpot虚拟机对象探秘(对象创建,对象内存布局,对象访问定位)

    以常用的HotSpot虚拟机和JAVA内存区域堆为例,探讨对象的创建,对象的内存布局以及对象的访问定位 一.对象的创建 1)类加载:虚拟机遇到一条new指令时,先检测这个指令的参数能否在常量池中定位到 ...

  10. Java内存区域与内存溢出异常--HotSpot虚拟机对象探秘

    以常用的HotSpot和常用的Java堆为例,深入探讨HotSpot虚拟机在Java堆中对象分配.布局和访问的全过程 1.对象的创建 ①虚拟机遇到一条new指令后,首先将去检查这个指令的参数是否能够在 ...

随机推荐

  1. apache环境.htaccess设置301跳转及常用.htaccess技巧整理

    apache环境.htaccess设置301跳转及常用.htaccess技巧整理 无论是Nginx,还是Apache都各自有优势,对于我们普通用户而言基本上也没有多大的区别.在虚拟主机环境中,基本上都 ...

  2. 阿里巴巴Java开发手册(华山版)

    插件下载地址: https://github.com/alibaba/p3c 2018年9月22日,在2018杭州云栖大会上,召开<码出高效:Java 开发手册>新书发布会,并宣布将图书所 ...

  3. js 动态加载 jq

    var script=document.createElement("script"); script.type="text/javascript"; scri ...

  4. H3C 开局设置

    简介: 系统菜单  即 [H3C] 模式 一:恢复出厂设置 这个没什么说的,必须Console连接. 连上以后,在启动时Ctrl+B,进入管理启动菜单,删除文件,删除配置文件然后重启即可. Ctrl+ ...

  5. Oracle Spatial分区应用研究之八:不同分区粒度在1.5亿要素量级下的查询性能

    以土地调查地类图斑层作为测试数据,共计约1.5亿条要素.随机生成90次各比例尺的查询范围,在ORACLE 11gr2数据库中进行空间查询,记录查询耗时.最后计算平均值和第90百分位数,结果如下图所示: ...

  6. Java生成艺术二维码也可以很简单

    原文点击: Quick-Media Java生成艺术二维码也可以很简单 现在二维码可以说非常常见了,当然我们见得多的一般是白底黑块,有的再中间加一个 logo,或者将二维码嵌在一张特定的背景中(比如微 ...

  7. 【记录】【java】反射设值取值

    1.设值 /** * 根据属性名设置属性值 * * @param fieldName * @param object * @return */ public boolean setFieldValue ...

  8. 【转帖】Kafka入门介绍

    Kafka入门介绍 https://www.cnblogs.com/swordfall/p/8251700.html 最近在看hdoop的hdfs 以及看了下kafka的底层存储,发现分布式的技术基本 ...

  9. 51book机票接口对接,吐血整理(含PHP封装代码)

    前言 最近在对接51book的机票接口,遇到了挺多坑,所以整理一份作为记录 机票有两个不同的接口,一个是机票,另一个是保险 一.申请 要接51book的机票,首先是要申请账号,这时候应该是有客户经理跟 ...

  10. LInux基础(04)项目设计一(理解链表管理协议的代码架构)

    要设计好一个项目必须要有一个健全的代码框架 一个结构体内有数据域和处理数据的函数指针, 先实现管理链表的函数 增加节点  删除节点  清空链表  遍历节点对每个节点进行操作 再实现协议的注册 把对象s ...