深入理解JVM(4)——对象的创建和访问
1、对象的创建
在语言层面上,创建对象(例如克隆,反序列化)通常仅仅是一个new关键字而已。
在虚拟机中,对象(文中讨论的对象限于普通 Java 对象,不包括数组和 Class 对象等)的创建过程如下:

1.1、分配内存
空间分配的两种方式
- 指针碰撞:当已分配空间被集中存放,已分配和未分配空间使用一个指针来标记时,分配新的空间只需要移动该指针即可,此方法为指针碰撞。适用于 GC 算法会做 Compact 的情况。
- 空闲列表:当已分配的空间是分散存放时,虚拟机必须维护一个记录了哪些内存块是可用的列表,此为空闲列表,需要分配新空间时只需要从该列表中获取。
分配方式的选择取决于由Java堆是否规整,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。 因此,在使用 Serial、 ParNew 等带 Compact 过程的收集器时,系统采用的分配算法是指针碰撞,而使用 CMS 这种基于 Mark-Sweep 算法的收集器时,通常采用空闲列表。
解决空间分配线程安全问题的两种方式
- CAS方式失败重试:顾名思义,遇上分配时的线程冲突时,会再次进行空间分配直至成功。实现简单直观但是效率较低
- 空间划分:为每个线程分配单独的一块空间,该空间只用来给该线程做创建对象分配空间时使用,这单独的空间被称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。当该线程的 TLAB 分配光了后,才需要同步锁定,效率较高。是否使用TLAB可以通过虚拟机参数 -XX:+/-UseTLAB 指定。
2、对象的内存布局
2.1、设置对象头
对象头包含两部分信息:
- 运行时数据(hash码、GC分代年龄、锁状态标志、 线程持有的锁、 偏向线程ID、 偏向时间戳等),这部分数据被称为 Mark Word。
- 类型指针,用来说明该对象是哪个类的实例。
2.2、设置对象实例数据
对象的实例数据主要是根据 JAVA 代码的编写生成的,包括父类在内的各种类型的字段,其存储顺序受虚拟机分配策略参数及代码中字段定义顺序的影响。
虚拟机安排字段的方式:
- 相同宽度的字段放在一起
- 父类的字段放在子类的前面
- 窄小的变量也会被安排在父类的字段空隙中(C++的内存安排规则,HotSpot VM是由C++语言编写)
2.3、填充字段
HotSpot VM要求对象的起始位置必须是8字节的整数倍,也就是说对象必须是8字节的整数倍,所以需要填充占位(这也是一句C++的规则来的)。
3、对象的访问
JAVA 程序访问对象需要通过栈上的 reference 数据操作堆上的具体对象。reference 对对象的访问方式主要为句柄和直接指针两种。
句柄访问
Java堆中将会划分出一块内存来作为句柄池,reference中存储的是对象的句柄地址,句柄中包含了对象实例数据与类型数据各自的具体地址信息。

直接指针访问
reference中存储的直接就是对象地址

句柄访问方式的好处是 reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。
直接指针访问方式的好处是速度更快,它节省了一次指针定位的时间开销。
虚拟机Sun HotSpot 使用的是直接指针访问。
深入理解JVM(4)——对象的创建和访问的更多相关文章
- 深入理解JVM(二)--对象的创建
Java是一门面向对象的语言,在Java程序运行的过程中,无时无刻都会有对象被创建出来,在程序语言中,创建对象(例如克隆,反序列化)通常仅仅是一个new关键字,但是在虚拟机中是怎样的呢?本文主要了解一 ...
- JVM中对象的创建过程
JVM中对象的创建过程如以下流程图中所示: 对其主要步骤进行详细阐述: 为新生对象分配内存: 内存的分配方式: 指针碰撞:假设Java堆中内存是绝对规整的,所有用过的内存放在一边,空闲的内存在另一边, ...
- 深入理解java虚拟机---对象的创建过程(八)
1.对象的创建过程 由于类的加载是一个很复杂的过程,所以这里暂时略过,后面会详细讲解,默认为是已加载过的类.着重强调对象的创建过程. 注意: 最后一步的init方法是代码块和构造方法. 以上是总图,下 ...
- JVM(三) 对象的创建过程
1.对象的创建过程 1.1 . 给对象分配内存 对象的内存分配有两种方式,一种是指针碰撞另外一种是空闲列表的方式,堆是否规整由我们垃圾回收器来决定的 ,如果垃圾回收带有我们的压缩算法,那么他会规整的分 ...
- 理解JVM之对象的生命周期
1.对象的创建 1) 当虚拟机遇到一条new的指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载,解析和初始化过. 2) 在类加载检查通 ...
- Java虚拟机-对象的创建和访问
一.对象的创建: 创建对象在java上面是很简单的,使用new关键字就可以了,但是其实在虚拟机中,java对象的创建是一个复杂的过程. 当java虚拟机遇到一个new的指令的时候,对象创建的程序正式启 ...
- 【Java 它 JVM】对象的创建过程
虚拟机会new 指令: 1.检查指令的参数可在对类的符号引用的恒定饮食定位,并检查是否已装上代表这个类的符号引用.分析和初始化.假设没有.您必须运行相应的类加载过程. 2.类加载通过审查,虚拟机将分配 ...
- 深入理解JVM(三) -- 对象的内存布局和访问定位
一 对象的内存布局: 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header),实例数据(Instance Data)和对齐填充(Padding). HotSpot的对 ...
- JVM之对象的创建简要流程
随机推荐
- 程序员利器Tmux使用手册
转:https://blog.csdn.net/chenqiuge1984/article/details/80132042
- python3 set(集合)
add(增加元素) name = set(['Tom','Lucy','Ben']) name.add('Juny') print(name) #输出:{'Lucy', 'Juny', 'Ben', ...
- Java 集合系列(二)—— ArrayList
ArrayList ArrayList 是通过一个数组来实现的,因此它是在连续的存储位置存放对象的引用,只不过它比 Array 更智能,能够根据集合长度进行自动扩容. 假设让我们来实现一个简单的能够自 ...
- 使用docker swarm集群心得
本片关于使用docker swarm 集群心得,也是一些经验吧!过程描述可能简单! 根据一些公司使用经历接收一下问题并针对问题作出应对策略 1.docker swarm集群 主节点数必须是单数,也就是 ...
- tcp、udp、ip、icmp报文格式分析
TCP .UDP .IP. ICMP协议报文格式分析 Tcp报文格式: Wireshark抓包如图: 源端口/目的端口(16bit): 在TCP报文中包涵了源端口/目的端口,源端口标识了发送进程,目的 ...
- Python爬虫【实战篇】百度贴吧爬取页面存到本地
先上代码 import requests class TiebaSpider: def __init__(self, tieba_name): self.tieba_name = tieba_name ...
- Vue 自定义一个插件的用法、小案例及在项目中的应用
1.开发插件 install有两个参数,第一个是Vue构造器,第二个参数是一个可选的选项对象 MyPlugin.install = function (Vue, options) { // 1 ...
- Analyzing 'enq: HW - contention' Wait Event (Doc ID 740075.1)
Analyzing 'enq: HW - contention' Wait Event (Doc ID 740075.1) In this Document Symptoms Cause ...
- (二)Basic Concepts 基本概念
Basic Concepts There are a few concepts that are core to Elasticsearch. Understanding these concepts ...
- python之shutil
''' shutil 用来处理 文件 文件夹 压缩包 的模块 ''' import shutil # 拷贝文件内容 shutil.copyfileobj(open('old.xml', 'r'), o ...