一、对象的内存布局

        以Hotspot虚拟机为例,对象在内存中的结构可以分为三部分:对象头(header)、实例数据(instance data)、对齐填充(padding)。

1.1.对象头

        对象头的结构大体相似,但不同JVM的具体实现使得它们略有差别。一般来说,对象头都包含了标记字、类型指针两部分信息,如果对象是数组,还会额外包含数组长度信息。

1.1.1.标记字

        存储对象自身的运行时数据(即状态),包括哈希码、GC分代年龄、锁状态标志、线程持有锁、偏向线程id、偏向时间戳等。它们的存储结构类似于C语言中的“位字段”,官方称之为“Mark Word(标记字)”。“标记字”以“字”作为基本的存储单元,即在32位虚拟机中,数据长度为32bit;而在64位虚拟机中,数据长度为64bit。
        以32bit虚拟机为例,有固定的2bit用于存储锁标志位,随着锁标志位值不同,其他位存储的内容与位长度也不同。这一点类似于C语言中的联合结构(union),且联合的每一个成员都是位字段结构。

1.1.2.类型指针

        类型指针即对象指向它的类元数据(class metadata)的指针,虚拟机通过该指针确定这个对象是哪个类的实例。但需要注意的是,并非所有虚拟机实现中都会在对象头包含类型指针,也可以采用其他方式保留对象的类型信息。

1.1.3.数组长度

        在java中,数组也属于对象,那么理所当然的需要维护数组长度,该信息存放在对象头中。
 

1.2.实例数据

        实例数据即对象的字段(或称为成员变量)存储的数据信息,包含了从父类继承及自己定义的所有字段。且字段在内存中存储的顺序并不等于类中的定义顺序,它受到虚拟机策略的影响(主要考虑到内存对齐以及使用率的问题)。
 

1.3.对齐填充

        类似于C中结构体struct的内存对齐,java对象的内存位置也需要对齐。
        我们常用的Hotspot虚拟机要求每个对象的起始地址为8字节的整数倍,也就是说,若一个对象结束地址非8字节整数倍,则需要占位符进行填充以保证对齐。
 

二、对象的访问定位

        虚拟机规定,需要通过栈上的“reference(引用)”来操作具体对象。对于该规定,目前有两种主流的实现方式:
  • 通过句柄(handler)实现:该种方式会在堆中划出一块“句柄池”内存空间,每个栈上的引用直接指向句柄池中的句柄,而句柄中又会维护对象指针和类型指针。使用句柄带来的好处是,栈上的reference存储稳定的句柄地址,GC造成的对象移动只会导致句柄中相应的指向地址改变,而reference地址不改变。

  • 通过直接指针(direct point)实现:即在对象的对象头中维护类型指针。栈的reference指向对象,而对象头中的类型指针指向对象类型数据。使用直接指针的好处是,对象的访问速度快,节省了指针二次寻址的开销。
 
 

三、对象的创建过程

        对象的创建过程要经历以下几个阶段:

3.1.类加载

  • 检查到new指令;
  • 虚拟机检查在常量池中是否有该类的符号引用,包括该符号引用代表的类是否已被加载、解析、初始化;
  • 没有,则先加载类(加载过程后续章节会详细讲述);有的话,直接创建对象;

3.2.内存分配

(1)内存分配的方式
         一个对象所需内存在类加载时便可确定,内存分配方式有两种:
  • 指针碰撞法:若java堆中内存是绝对规整的,所有用过内存都放到一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那分配内存就仅仅是把指针向空闲空间那边挪动一段与对象大小相等的距离;
  • 空闲列表法:若堆内存不规整,就无法通过简单的移动指针分配内存。这种情况下虚拟机会维护一个列表记录哪些内存可用,分配时查找并更新列表;
        使用哪种方式取决于内存是否规整,而内存是否规整又取决于垃圾收集器的GC算法。典型如serial、parnew这两种垃圾收集器,它们在GC时带有压缩整理的功能,因此系统会采用“指针碰撞”的方式分配内存;而CMS这种基于Mark-Sweep(标记-清除)算法的垃圾收集器,则会采用“空闲列表法”分配内存。
(2)内存分配的安全
        需要注意的是,若多个线程同时申请分配内存,如果不加以同步控制,则会导致内存分配不对。不同的虚拟机会采用不同的机制避免线程安全问题:
  • 同步锁定:通过CAS配上失败重试的方式保证更新操作的原子性。注:CAS,即CPU硬件同步原语,全称为compare and swap(比较并交换),若比较不对则失败;
  • TLAB:即线程分配缓冲区。在堆中预先为每个线程分配一小块内存,线程在各自分配的内存上进行内存分配来保证安全。只有当TLAB用尽并申请新的TLAB时,才进行同步锁定。

3.3.内存初始化

        内存初始化指的是将对象分配到的内存所有位重置为0(不含对象头)。若对象通过TLAB分配的,该过程会提前至“内存分配”执行.

3.4.对象头初始化

        设置对象的对象头信息。

3.5.对象实例数据初始化

        设置对象的实例数据信息,即成员变量值。只有这步完成了,一个真正的对象才产生并能提供给我们使用。

05-JVM对象探秘的更多相关文章

  1. JVM总结(一):概述--JVM对象探秘

    这一节我们来讨论一下JVM对象建立过程. JVM对象探秘 对象的建立 对象的内存布局 对象的访问定位 JVM对象探秘 对象的建立 对象的建立过程   图一:对象建立过程 1.类加载检查. 当JVM检测 ...

  2. JVM对象创建

    1.JVM对象创建:java程序运行过程中,无时无刻都有对象被创建出来.在语言层面上就是new关键字. 2.JVM对象创建过程: (1)JVM遇到一条new指令后,首先会去常量池中,检查这个指令的参数 ...

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

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

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

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

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

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

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

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

  7. 阿里面试官:小伙子,你给我说一下JVM对象创建与内存分配机制吧

    内存分配机制   逐步分析 类加载检查: 虚拟机遇到一条new指令(new关键字.对象的克隆.对象的序列化等)时,会先去检查这个指令的参数在常量池中定位到一个类的符号引用,并且这个符号引用代表的类是否 ...

  8. JAVA虚拟机之对象探秘

    上一章主要写到了JVM中运行时数据区域各个部分的功能及其作用.上一章说到了对象是分配在堆上面的,所以接下来我们写到对象在堆内存中是如何创建.如何布局.如何访问.1. 对象的创建 在java程序中对象的 ...

  9. JVM对象分配和GC分布【JVM】

    最近在学习java基础结构,刚好学到了jvm,总结了以下并可以结合思维导图认识以下Jvm的对象: 栈:什么是栈? 先说一下栈的数据结构吧,栈它是一种先进后出的数据结构(FILO),跟队列刚好相反(先进 ...

随机推荐

  1. mysql中与 in 相反的语句 find_in_set('数据',字段名)

    在 mysql 中,我们经常用 in 来查询众多数据中是否有数据表字段中的值: 如果我们在数据表的字段中添加了很多值,然后查询某个值是否是这个字段中众多值的一个时可以用 find_in_set('数据 ...

  2. Visual C++中MFC消息的分类

    Visual C++中MFC消息的分为三类:标准(窗口)消息.命令消息.控件消息. 1.标准(窗口)消息:窗口消息一般与窗口内部运作有关,如创建窗口,绘制窗口,销毁窗口,通常,消息是从系统发到窗口,或 ...

  3. 微信小程序的postMessage不实时?

    最近在开发小程序的时候用到了wx.postMessage()这个API,在使用前我一直认为wx.postMessage()可以在小程序和H5中实时的传递信息,可以依靠这个API开发一个小程序的brid ...

  4. java 时间日期

    Java 日期时间 java.util 包提供了 Date 类来封装当前的日期和时间. Date 类提供两个构造函数来实例化 Date 对象. 第一个构造函数使用当前日期和时间来初始化对象. Date ...

  5. oracle本地安装注意事项

    这两天组员在本地windows上安装oracle数据库,安装完各种问题,pl/sql developer以及tns_admin配置以及tnsnames.ora和sqlnet.ora listener. ...

  6. vue+element-ui中的图片获取与上传

    vue+element-ui中的图片获取与上传 工作上接触了一下图片的处理,图片的格式是文件流, 记录如下. 请求图片 请求图片的时候,带上{ responseType: 'blob' }, 否则图片 ...

  7. springsource-tool-suite插件下载

    下载地址:    https://spring.io/tools3/sts/all/ 下载页面上的 update sites archives文件

  8. vue2.0 移动端,下拉刷新,上拉加载更多插件,修改版

    在[实现丰盛]的插件基础修改[vue2.0 移动端,下拉刷新,上拉加载更多 插件], 1.修改加载到尾页面,返回顶部刷新数据,无法继续加重下一页 2.修改加载完成文字提示 原文链接:http://ww ...

  9. windows简易使用composer 安装国内镜像

    1.下载composer.phar文件 地址: https://getcomposer.org/download/  从下面选择一个 2.下载成功,新建项目(找到已有的项目文件夹)文件夹(D:\PHP ...

  10. php5.4以上 mysqli 实例操作mysql 增,删,改,查

    <?php //php5.4以上 mysqli 实例操作mysql header("Content-type:text/html;charset=utf8"); $conn ...