深入理解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之对象的创建简要流程
随机推荐
- git rebase 使用详解
rebase 假设你现在基于远程分支"origin",创建一个叫"mywork"的分支. $ git checkout -b mywork origin 现 ...
- 通过Erlang构建TCP服务应用案例(最原始方式)
文章来源:公众号-智能化IT系统. 案例介绍 本文介绍的案例是TCP网络服务器的构建,用最原始的方式(非OTP).其功能很简单,通过网络TCP接口接收数据,按照指定的格式解析,并把数据存储至Mongo ...
- python调用C程序代码
DHT11的驱动使用C语言编写 然后用python调用C的程序 显示温湿度 pycall.py文件如下: #!/usr/bin/env python # -*- coding:utf-8 -*- ...
- 使用Python的Mock库进行PySpark单元测试
测试是软件开发中的基础工作,它经常被数据开发者忽视,但是它很重要.在本文中会展示如何使用Python的uniittest.mock库对一段PySpark代码进行测试.笔者会从数据科学家的视角来进行描述 ...
- RabbitMQ持久化
我们知道,如果消息接收端挂了,消息会保存在队列里.下次接收端启动就会接收到消息. 如果RabbitMQ挂了怎么办呢?这时候需要将消息持久化到硬盘 消息发送端:producer ........... ...
- 进程间数据传递:Queue,Pipe 进程间数据共享:Manager
1.使用multiprocessing模块的Queue实现数据传递 ''' 进程间通讯: Queue,用法跟线程里的Queue一样,put,get 线程queue没有做序列化,进程queue做序列化了 ...
- linux磁盘IO读写性能优化
在LINUX系统中,如果有大量读请求,默认的请求队列或许应付不过来,我们可以 动态调整请求队列数来提高效率,默认的请求队列数存放在/sys/block/xvda/queue/nr_requests 文 ...
- Spring Boot 学习之路二 配置文件 application.yml
一.创建配置文件 如图所示,我们在resources文件夹中新建配置文件application.yml 结构图 二.一些基本配置 server: port: 8090 //配置端口 session ...
- 贷款资讯类APP、贷款资讯网站廉价卖,需要的进来看看
[app介绍]卡贷资讯app为您提供信用卡申请攻略及借款资讯以及贷款口子,让你借钱借款路上不再愁.[功能特点]1.资讯:聚合各种贷款资讯知识,掌握核心信用卡申请攻略,借款借钱不亏,亦不被骗:2.工具: ...
- linux 网卡的混杂模式的取消
1.Linux下网卡常用的几种模式说明: 广播方式:该模式下的网卡能够接收网络中的广播信息. 组播方式:设置在该模式下的网卡能够接收组播数据. 直接方式:在这种模式下,只有目的网卡才能接收该数据. 混 ...