Java对象的创建、内存布局和访问定位
在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
虚拟机对象的对象头一般包含两部分信息,第一部分用于存储对象自身的运行时数据,例如HashCode
、GC
分代年龄、锁状态标志、线程持有锁、偏向线程ID、偏向时间戳等信息。官方称这部分数据为Mark Word
。在32
位和64
位的JVM
中,这部分数据分别为32bit
和64bit。
另一部分用于存储对象的类型指针,该指针指向它的类元数据,JVM
通过这个指针确定对象是哪个类的实例。在32
位JVM
中,指针的长度为32bit
,在未开启压缩指针的64
位JVM
中,该指针的长度为64bit
,如果开启压缩指针,那么为32bit
。
需要注意的是:如果对象是一个数组,那么对象头还需要有额外的空间用于存储数组的长度,并且这部分数据也随着JVM
位数的不同而不同:32
位的JVM
上,该区域的长度为32bit
,在64
位未开启压缩指针的JVM
中,这部分数据的长度为64bit
,否则为32bit
。
实例数据
实例数据部分是对象真正存储有效信息的区域,存储了代码中定义的各种字段的内容,包括从父类继承下来的字段和子类中定义的字段。
对齐填充
对齐填充这部分不是必须存在的,这部分仅仅是起着占位符的作用。由于HotSpot
虚拟机的自动内存管理系统要求对象的起始地址必须是8
字节的整数倍,因此当对象实例部分数据没有对齐时,就需要对剩余的部分进行填充。
三、对象的访问定位
总结
1.HotSpot虚拟机在Java堆上创建对象的过程?
①分配内存
②虚拟机设置对象头
③对象初始化
2.分配内存空间的两种方式?
指针碰撞和空闲列表
3.如何保证线程安全?
Java对象的创建、内存布局和访问定位的更多相关文章
- JVM 专题十二:运行时数据区(七)对象的实例化内存布局与访问定位
1. 对象的实例化 1.1 创建对象的方式 new 最常见的方式 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 Class的newInstance() ...
- JVM运行时数据区--纵向补充--对象的实例化内存布局与访问定位
对象的实例化 创建对象的方式 1.new:最常见的方式(本质是构造器) 变形1 : Xxx的静态方法 变形2 : XxBuilder/XxoxFactory的静态方法 2.Class的newInsta ...
- 【JVM之内存与垃圾回收篇】对象实例化内存布局与访问定位
对象实例化内存布局与访问定位 从各自具体的内存分配上来讲 new 的对象放在堆中 对象所属的类型信息是放在方法区的 方法当中的局部变量放在栈空间 这 new 的对象怎么把三块粘合到一起 就是这章的内容 ...
- 关于Java的对象,锁和对象的内存布局、访问定位
1. 对象的创建和分配 创建对象(如克隆.反序列化)通常仅仅一个new关键字,但在虚拟机中,对象的创建的过程需要如下步骤: 类加载检查 先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并 ...
- 浅谈Java虚拟机内存中的对象创建,内存布局,访问定位
参考于 深入理解Java虚拟机 这里介绍HotSpot虚拟机(自带的虚拟机) 1.对象的创建 对于程序员来说,创建对象的方法: User user1 = new User(); User user2 ...
- Java对象创建的过程及对象的内存布局与访问定位
这里以HotSpot为例,且所说的对象指普通的Java对象,不包括数组和Class对象等. 1.对象创建的过程 1.类加载.解析.初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池中找到类的符 ...
- 【深入理解JVM】:Java对象的创建、内存布局、访问定位
对象的创建 一个简单的创建对象语句Clazz instance = new Clazz();包含的主要过程包括了类加载检查.对象分配内存.并发处理.内存空间初始化.对象设置.执行ini方法等. 主要流 ...
- java面试-对象的创建、内存布局、访问定位
一.对象的创建 1.虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载.解析和初始化过.如果没有,那必须先执行相应的 ...
- 深入理解Java虚拟机(二)、Java对象的创建,内存布局和访问定位
对象的创建: Object obj = new Object(); 常量池中是否有Ljava.lang.Object
随机推荐
- CentOS7 Python2 和Python3 共存(Python3安装)【转】
1.查看是否已经安装Python CentOS 7.2 默认安装了python2.7.5 因为一些命令要用它比如yum 它使用的是python2.7.5. 使用 python -V 命令查看一下是否安 ...
- supervusor常遇到的问题
1.unix:///tmp/supervisor.sock refused connection supervisord -c /etc/supervisord.conf 2.Unlinking s ...
- 浅析data:image/png;base64的应用
...我也是加一个网安交流群发现了他们的入群密码是这个 数据:图像/ PNG; BASE64,iVBORw0KGgoAAAANSUhEUgAAANwAAAAoCAIAAAAaOwPZAAAAAXNSR ...
- ctf学习(web题二)
web 下面是做bugku上一些web的总结 内容链接
- SSL 原理及 https 配置
目录 1. SSL 原理 1.1. SSL 简介 1.2. 主要概念 1.3. 建立安全连接的过程 2. https 配置 (以 nginx 为例) SSL 原理 SSL 简介 SSL (Secure ...
- reportComplaints.js: Uncaught TypeError: Cannot read property 'message' of undefined
vonic 中遇到这么个问题, 一直提示我未定义, 可是明明有定义 var tab={ message:{ number:'', title:'' } } var id= { template: '# ...
- 设计模式のFacadePattern(外观模式)----结构模式
一.产生背景 外观模式(Facade Pattern)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口.这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性. ...
- 深入理解Ribbon之源码解析
什么是Ribbon Ribbon是Netflix公司开源的一个负载均衡的项目,它属于上述的第二种,是一个客户端负载均衡器,运行在客户端上.它是一个经过了云端测试的IPC库,可以很好地控制HTTP和TC ...
- 51nod 省选联测 R2
51nod 省选联测 R2 上场的题我到现在一道都没A,等哪天改完了再写题解吧,现在直接写第二场的. 第二场比第一场简单很多(然而这并不妨碍我不会做). A.抽卡大赛:http://www.51nod ...
- P1460 健康的荷斯坦奶牛 Healthy(DFS)
思路:这道题还是用了小小的剪枝,这里要注意的是该题有很多中构建树的顺序,但是,在这众多顺序中不一定都能保证输出的方案字典序最小. 构建搜索树:如图构建 剪枝,emmm,看代码: #include< ...