Java运行时数据区中,我们知道了虚拟机内存的概况,本文介绍虚拟机内存中的数据的其它细节,如对象如何创建、如何布局以及如何访问。

基于实用的原则,这里以HotSpot虚拟机和常用的内存区域Java堆为例,来探讨HotSpot虚拟机在Java堆中对象的分配、布局和访问的全过程。

一、对象的创建

1.分配内存

虚拟机遇到new指令时,首先检查该指令的参数是否在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程。可参考类加载机制

类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。

<一>如何划分内存空间

内存分配方式有两种:

①指针碰撞(Bump the Pointer)分配方式

假设Java堆中内存是绝对规整的,所有用过的内存在一边,空闲的内存在另一边,中间放着一个指针作为分界点,那分配内存就仅仅是把该指针向空闲的那边挪动一段与对象大小相等的距离,这种分给方式称为指针碰撞。

②空闲列表(Free List)分配方式

如果Java堆中的内存并不是规整的,已使用内存与空闲内存相互交错,就不能简单进行指针碰撞了。虚拟机必须维护一个列表,记录那些内存是可用的,在分配时从列表中找到一块足够大的空间分配给对象实例,并更新列表上的记录,这种分配方式称为空闲列表。

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整是由采用的垃圾收集器是否带有压缩整理功能决定的。因此,使用Serial、ParNew等带有Compact过程的收集器时,系统采用的分配算法是指针碰撞,而使用CMS这种基于Mark-Sweep算法的收集器时,通常采用空闲列表。

<二>创建对象时如何保证线程安全

有两种方案

方案①:对分配内存空间的动作进行同步处理

虚拟机采用CAS加失败重试的方式保证更新操作的原子性

方案②:把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一个小块内存,称为本地线程分配缓冲(TLAB,thread Local Allocation Buffer)。哪个线程要分配内存,就在哪个线程的TLAB上分配,只有TLAB用完并重新分配新的TLAB时,才需要同步锁定。虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定。

内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),如果使用TLAB,这一工作过程也可以提前至TLAB分配时进行。这一步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序访问到这些字段的数据类型所对应的零值。

2.虚拟机对对象进行设置

接下来,虚拟机要对对象进行必要的设置,例如这个对象时哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象头中

3.init初始化

上面工作都完成后,从虚拟机视角看,对象已经创建成功了,但从Java程序的视角看,对象还没进行初始化,所有的字段都还为零值,接下来执行<init>进行初始化。

所以一般来说(由字节码中是否跟随invokespecial指令决定),执行new指令后会接着执行<init>方法进行初始化,这样才完成了对象的创建。

二、对象的内存布局

在 HotSpot 虚拟机中,对象在内存中存储布局分为 3 块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)。

对象头

HotSpot虚拟机对象的对象头一般包含两部分信息,第一部分用于存储对象自身的运行时数据,例如HashCodeGC分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等信息。官方称这部分数据为Mark Word。在32位和64位的JVM中,这部分数据分别为32bit64bit。

另一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM通过这个指针确定对象是哪个类的实例。在32JVM中,指针的长度为32bit,在未开启压缩指针的64JVM中,该指针的长度为64bit,如果开启压缩指针,那么为32bit

需要注意的是:如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,并且这部分数据也随着JVM位数的不同而不同:32位的JVM上,该区域的长度为32bit,在64位未开启压缩指针的JVM中,这部分数据的长度为64bit,否则为32bit

实例数据

实例数据部分是对象真正存储有效信息的区域,存储了代码中定义的各种字段的内容,包括从父类继承下来的字段和子类中定义的字段。

对齐填充

对齐填充这部分不是必须存在的,这部分仅仅是起着占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象的起始地址必须是8字节的整数倍,因此当对象实例部分数据没有对齐时,就需要对剩余的部分进行填充。

三、对象的访问定位

总结

1.HotSpot虚拟机在Java堆上创建对象的过程?

①分配内存

②虚拟机设置对象头

③对象初始化

2.分配内存空间的两种方式?

指针碰撞和空闲列表

3.如何保证线程安全?

Java对象的创建、内存布局和访问定位的更多相关文章

  1. JVM 专题十二:运行时数据区(七)对象的实例化内存布局与访问定位

    1. 对象的实例化 1.1 创建对象的方式 new 最常见的方式 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 Class的newInstance() ...

  2. JVM运行时数据区--纵向补充--对象的实例化内存布局与访问定位

    对象的实例化 创建对象的方式 1.new:最常见的方式(本质是构造器) 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 2.Class的newInsta ...

  3. 【JVM之内存与垃圾回收篇】对象实例化内存布局与访问定位

    对象实例化内存布局与访问定位 从各自具体的内存分配上来讲 new 的对象放在堆中 对象所属的类型信息是放在方法区的 方法当中的局部变量放在栈空间 这 new 的对象怎么把三块粘合到一起 就是这章的内容 ...

  4. 关于Java的对象,锁和对象的内存布局、访问定位

    1. 对象的创建和分配 创建对象(如克隆.反序列化)通常仅仅一个new关键字,但在虚拟机中,对象的创建的过程需要如下步骤: 类加载检查 先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并 ...

  5. 浅谈Java虚拟机内存中的对象创建,内存布局,访问定位

    参考于 深入理解Java虚拟机 这里介绍HotSpot虚拟机(自带的虚拟机) 1.对象的创建 对于程序员来说,创建对象的方法: User user1 = new User(); User user2 ...

  6. Java对象创建的过程及对象的内存布局与访问定位

    这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 1.类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符 ...

  7. 【深入理解JVM】:Java对象的创建、内存布局、访问定位

    对象的创建 一个简单的创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查.对象分配内存.并发处理.内存空间初始化.对象设置.执行ini方法等. 主要流 ...

  8. java面试-对象的创建、内存布局、访问定位

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

  9. 深入理解Java虚拟机(二)、Java对象的创建,内存布局和访问定位

    对象的创建: Object obj = new Object(); 常量池中是否有Ljava.lang.Object

随机推荐

  1. spyder 快捷键

    本文主要介绍了spyder的快捷键. 常用快捷键   快捷键 中文名称 Ctrl+R 替换文本 Ctrl+1 单行注释,单次注释,双次取消注释 Ctrl+4 块注释,单次注释,双次取消注释 F5 运行 ...

  2. liunx搭建DHCP服务器以及DHCP中继服务器

    liunx搭建DHCP服务器以及DHCP中继服务器 一.实验拓扑 二.实验条件 虚拟机取消VMnet1和VMnet8的dhcp动态获取ip地址,以免影响实验 DHCPserver 网关以及DHCP中继 ...

  3. java 一个实例

     this 代替

  4. win10系统中如何解决cmd中的路径和现在电脑的用户名不一致

    假设原用户名老王,已删除,但是cmd后路径还是C:\Users\老王>,这与现在用户laowng不一致了需改为C:\Users\laowang>. .先新建一个管理员账户laowang,然 ...

  5. 【2018.08.19 C与C++基础】编程语言类型系统简介(草稿)

    还是先占坑,等理顺了思路再写,学过的东西总是无法系统化,感觉什么都知道一点,但一深入却是一脸懵逼. 这真的是个问题,看似很努力,却无法成为一个master. 参考链接: 1. 编程语言的类型系统为何如 ...

  6. Python语法基础-函数,类以及调试处理

    [TOC] 1. 函数的定义 python中函数有两种: python自带的函数 用户定义函数 返回多个值 原来返回值是一个tuple!但是,在语法上,返回一个tuple可以省略括号,而多个变量可以同 ...

  7. #005Python实验楼基本操作学习笔记

    Ctrl + D 输入一个 EOF 字符来退出解释器,也可以键入 exit() 来退出解释器. 打开 Xfce 终端,键入 vim helloworld.py 来启动 Vim 并编辑 hellowor ...

  8. Loj#6183. 看无可看

    Loj#6183. 看无可看 题目描述 首先用特征根求出通项公式\(A_n=p\cdot 3^n+q\cdot(-1)^n\).通过给定的\(f_0,f_1\)可以解出\(p,q\). 然后我们要求的 ...

  9. 【vue】vue +element 搭建项目,vuex中的store使用

    概述: 每一个 Vuex 应用的核心就是 store(仓库).“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state).Vuex 和单纯的全局对象有以下两点不同: Vuex 的 ...

  10. 006_饿了么大前端总监sofish帮你理清前端工程师及大前端团队的成长问题!

    作者|Sofish编辑|小智 & 尾尾本文是前端之巅向 sofish 的约稿<什么样的人可以称为架构师?>.采访< 饿了么大前端团队究竟是如何落地和管理的?>以及 so ...