深入浅出JVM(一)之Hotspot虚拟机中的对象

本篇文章思维导图

image-20210330233053370.png

对象的创建

对象的创建可以分为五个步骤:检查类加载,分配内存,初始化零值,设置对象头,执行实例构造器

类加载检查
  • HotSpot虚拟机遇到一条new指令,会先检查能否在常量池中定位到这个类的符号引用,检查这个类是否类加载过

    • 没有类加载过就去类加载
    • 类加载过就进行下一步分配内存
分配内存

对象所需的内存在类加载完成后就可以完全确定

分配内存方式

虚拟机在堆上为新对象分配内存,有两种内存分配的方式:指针碰撞,空闲列表

  • 指针碰撞

    • 使用场景: 堆内存规整整齐

    • 过程: 使用过的空间放在一边,空闲的空间放在另一边,中间有一个指针作为分界点指示器,把新生对象放在使用过空间的那一边,中间指针向空闲空间那边挪动一个新生对象的内存大小的距离即可

image-20201028174425589.png

特点:简单,高效,因为要堆内存规整整齐,所以垃圾收集器应该要有压缩整理的能力

  • 空闲列表

    • 使用场景: 已使用空间和空闲空间交错在一起
    • 过程: 虚拟机维护一个列表,列表中记录了哪些内存空间可用,分配时找一块足够大的内存空间划分给新生对象,然后更新列表
    • 特点: 比指针碰撞复杂, 但是对垃圾收集器可以不用压缩整理的能力
分配内存流程

分配内存流程(栈--老年代--TLAB--Eden)

因为在堆上为对象分配内存,内存不足会引起GC,引起GC可能会有STW(Stop The World)影响响应

为了优化减少GC,当对象不会发生逃逸(作用域只在方法中,不会被外界调用)且栈内存足够时,直接在栈上为对象分配内存,当线程结束后,栈空间被回收,(局部变量也被回收)就不用进行垃圾回收了

开启逃逸分析-XX:+DoEscapeAnalysis满足条件的对象就在栈上分配内存

(当对象满足不会逃逸条件除了能够优化在栈上分配内存还会带来锁消除,标量替换等优化...)

image-20201124164550072.png

  1. 尝试该对象能不能在栈上分配内存
  2. 如果不符合1,且该对象特别的大,比如内存超过了JVM设置的大对象的值就直接在老年代上为它分配内存
  3. 如果这个对象不大,为了解决并发分配内存,采用TLAB 本地线程分配缓冲

TLAB 本地线程分配缓存

堆内存是线程共享的,并发情况下从堆中划分线程内存不安全,如果直接加锁会影响并发性能

为每个线程在Eden区分配小小一块属于线程的内存,类似缓冲区

哪个线程要分配内存就在那个线程的缓冲区上分配,只有缓冲区满了,不够了才使用乐观的同步策略(CAS+失败重试)保证分配内存的原子性

image-123.png

在并发情况下分配内存是不安全的(正在给A对象分配内存,指针还未修改,使用原来的指针为对象B分配内存),虚拟机采用TLAB(Thread Local Allocation Buffer本地线程分配缓冲)和CAS+失败重试来保证线程安全

  • TLAB:为每一个线程预先在伊甸园区(Eden)分配一块内存,JVM给线程中的对象分配内存时先在TLAB分配,直到对象大于TLAB中剩余的内存或TLAB内存已用尽时才需要同步锁定(也就是CAS+失败重试)
  • CAS+失败重试:采用CAS配上失败重试的方式保证更新操作的原子性
初始化零值

分配内存完成后,虚拟机将分配的内存空间初始化为零值(不包括对象头) (零值: int对应0等)

保证了对象的成员字段(成员变量)在Java代码中不赋初始值就可以使用

设置对象头

把一些信息(这个对象属于哪个类? 对象哈希码,对象GC分代年龄)存放在对象头中 (后面详细说明对象头)

执行init方法

init方法 = 实例变量赋值 + 实例代码块 + 实例构造器

按照我们自己的意愿进行初始化

对象的内存布局

对象内存信息

对象在堆中的内存布局可以分为三个部分:对象头,实例数据,对齐填充

  • 对象头包括两类信息(8Byte + 4Byte)

    1. Mark Word:用于存储该对象自身运行时数据(该对象的哈希码信息,GC信息:分代年龄,锁信息:状态标志等)

    2. 类型指针(对象指向它类型元数据的指针):HotSpot通过类型指针确定该对象是哪个类的实例 (如果该对象是数组,对象头中还必须记录数组的长度)

    类型指针默认是压缩指针,内存超过32G时为了寻址就不能采用压缩指针了

  • 实例数据是对象真正存储的有效信息

    1. 记录从父类中继承的字段和该类中定义的字段
    2. 父类的字段会出现在子类字段之前,默认子类较小的字段可以插入父类字段间的空隙以此来节约空间(+XX:CompactFields)
  • 对齐填充

    HotSpot要求对象起始地址必须是8字节整倍数

    所以任何对象的大小都必须是8字节的整倍,如果对象实例数据部分未到达8字节就会通过对齐填充进行补全

分析对象占用字节

Object obj = new Object(); 占多少字节?

导入JOL依赖

 <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
         <dependency>
             <groupId>org.openjdk.jol</groupId>
             <artifactId>jol-core</artifactId>
             <version>0.12</version>
         </dependency>

image-20201124171137539.png mark word : 8 byte

类型指针: 4 byte

对齐填充 12->16 byte

int[] ints = new int[5]; 占多少内存?

image-20201124171539813.png mark word:8 byte

类型指针: 4 byte

数组长度: 4 byte

数组内容初始化: 4*5=20byte

对齐填充: 36 -> 40 byte

父类私有字段到底能不能被子类继承?

image-20201124173533826.png

子类对象的内存空间中保存有父类私有字段,只是无法使用

栈-堆-方法区结构图

image-20210429190053375.png

对象的访问定位

Java程序通过栈上的reference类型数据来操作堆上的对象

访问方式

对象实例数据: 对象的有效信息字段等(就是上面说的数据)

对象类型数据: 该对象所属类的类信息(存于方法区中)

  • 句柄访问

image-20201109182633606.png - 在堆中开辟一块内存作为句柄池,栈中的reference数据存储的是该对象句柄池的地址,句柄中包含了对象实例数据和对象类型数据 - 优点: 稳定,对象被移动时(压缩或复制算法),只需要改动该句柄的对象实例数据指针 - 缺点: 多一次间接访问的开销

  • 直接指针访问

image-20201109182806454.png

栈中的reference数据存储堆中该对象的地址(reference指向该对象),但是对象的内存布局需要保存对象类型数据

优点: 访问速度快

缺点: 不稳定,对象被移动时(压缩或复制算法),需要改动指针

访问方式是虚拟机来规定的,Hotspot主要使用直接指针访问

总结

本篇文章主要从对象的创建流程(类加载、分配内存、初始化零值、设置对象头、执行实例方法)、对象的内存布局(对象头、实例数据、对齐填充)、访问对象的定位方式(直接指针访问、句柄访问)等层面详细介绍了对象,还在其中穿插了栈上分配、TLAB等内存分配优化以及分析对象占用具体空间

  • 参考资料
    • 《深入理解Java虚拟机》
    • 部分图片来源于网络

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/400387.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中国 AI 开课速度直逼美国 AI 颠覆性创新速度

原文链接&#xff1a; 中国 AI 开课速度直逼美国 AI 颠覆性创新速度 今日热帖&#xff0c;有网友发帖称&#xff1a;Sora 和 ChatGPT 告诉我们&#xff0c;美国确实是遥遥领先&#xff0c;而且还越拉越远。 是不是遥遥领先暂且不说&#xff0c;但领先我们的确是事实。 主要是…

多任务互斥及队列

一.互斥的引入 在FreeRTOS中&#xff0c;互斥&#xff08;Mutex&#xff09;是一种用于保护共享资源的机制。互斥锁可以确保同一时间只有一个任务能够访问共享资源&#xff0c;从而避免了竞态条件和数据不一致的问题。 FreeRTOS中互斥的引入方法&#xff1a; 创建互斥锁&#…

【笔记】【算法设计与分析 - 北航童咏昕教授】绪论

算法设计与分析 - 北航童咏昕教授 文章目录 算法的定义定义性质 算法的表示自然语言编程语言伪代码 算法的分析算法分析的原则渐近分析 算法的定义 定义 给定计算问题&#xff0c;算法是一系列良定义的计算步骤&#xff0c;逐一执行计算步骤即可得预期的输出。 性质 有穷性确…

【Linux】git操作 - gitee

1.使用 git 命令行 安装 git yum install git 2.使用gitee 注册账户 工作台 - Gitee.com 进入gitee&#xff0c;根据提示注册并登录 新建仓库 仓库名称仓库简介初始换仓库 3.Linux-git操作 进入仓库&#xff0c;选择“克隆/下载” 复制下面的两行命令进行git配置 然后将仓库clo…

c语言经典测试题2

1.题1 我们来思考一下它的结果是什么&#xff1f; 我们来分析一下&#xff1a;\\是转义为字符\&#xff0c;\123表示的是一个八进制&#xff0c;算一个字符&#xff0c;\t算一个字符&#xff0c;加上\0&#xff0c;应该有13个&#xff0c;但是strlen只计算\0前的字符个数。所以…

快速学习springsecurity最新版 (版本6.2)---用户认证

简介 ​ Spring Security 是 Spring 家族中的一个安全管理框架。目前比较主流的是另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富,但是shiro并不简便,这里轻量级安全框架更推荐国产安全框架satokensatoken官网 ​ 一般大型的项目都…

QT应用软件【协议篇】周立功CAN接口卡代码示例

文章目录 USBCAN系列CAN接口卡规格参数资料下载QT引用周立功的库安装sdk代码USBCAN系列CAN接口卡 USBCAN系列CAN接口卡兼容USB2.0全速规范,可支持1/2/4/8路CAN接口。采用该接口卡,PC机可通过USB连入CAN网络,进行CAN总线数据采集和处理,主要具备以下几大优势特点: 支持车载…

Matlab图像处理——图像编码解码

1.霍夫曼编码和解码 clear clc Iimread(lena.bmp); Iim2double(I)*255; [height,width]size(I); %求图像的大小 HWmatrixzeros(height,width); Matzeros(height,width); %建立大小与原图像大小相同的矩阵HWmatrix和Mat&#xff0c;矩阵元素为0。 HWmatrix(1,1)I(1,1); …

清洁力强的洗地机什么牌子最好?深度清洁的洗地机推荐

在相信很多人在做家务时&#xff0c;或许都会遇到一个尴尬的境地&#xff1a;虽然使用吸尘器清理了地面上的尘土和杂物&#xff0c;然后再使用拖把擦洗地板&#xff0c;但往往还是无法达到十分干净的效果。扫地机器人对于着色严重的垃圾&#xff0c;往往会出现越拖越脏的情况。…

Vue3之生命周期基础介绍

让我为大家介绍一下vue3的生命周期吧&#xff01; 创建阶段&#xff1a;setup 我们直接console.log就可以了 console.log("创建");挂载阶段&#xff1a;onBeforeMount(挂载前)、onMounted(挂载完毕) import { onBeforeMount, onMounted } from vue; // 挂载前 on…

【前端】Vue-Cli 快速创建Vue3项目及一些项目初始化相关

文章目录 前言1. 安装1.1 安装 Vue 脚手架1.2 创建项目1.3 本地运行项目 2. 推送到仓库2.1 远程仓库准备2.2 关于gitIgnore文件2.3 通过git推送至远程仓库 3. 补充与总结3.1 npm 版本是否要升级到最新&#xff1f;3.2 这个项目建议的各种版本3.3 一般前端gitIgnore文件3.4 推荐…

蚂蚁集团开始招聘华为鸿蒙应用研发工程师

早在2023年12月7日支付宝宣布将全面启动鸿蒙原生应用开发。华为表示&#xff0c;支付宝将基于HarmonyOS NEXT版本开发应用&#xff0c;给消费者带来全场景的新体验。头部应用伙伴的加入&#xff0c;大力推动了鸿蒙生态进一步完善。 就近期蚂蚁集团开始招聘华为鸿蒙应用研发工程…

【2024软件测试面试必会技能】Jmeter+ant+jenkins实现持续集成

jmeterantjenkins持续集成 一、下载并配置jmeter 首先下载jmeter工具&#xff0c;并配置好环境变量&#xff1b;参考&#xff1a;https://www.cnblogs.com/YouJeffrey/p/16029894.html jmeter默认保存的是.jtl格式的文件&#xff0c;要设置一下bin/jmeter.properties,文件内容…

成为高级性能测试:发现性能瓶颈掌握性能调优

当下云计算、大数据盛行的背景下&#xff0c;大并发和大吞吐量的需求已经是摆在企业面前的问题了&#xff0c;其中网络的性能要求尤为关键&#xff0c;除了软件本身需要考虑到性能方面的要求&#xff0c;一些硬件上面的优化也是必不可少的。 作为一名测试工作者&#xff0c;对…

SICTF Round#3 の WP

Misc 签到 SICTF{1f4ce05a-0fed-42dc-9510-6e76dff8ff53} Crypto [签到]Vigenere 附件内容&#xff1a; Gn taj xirly gf Fxgjuakd, oe igywnd mt tegbs mnrxxlrivywd sngearbsw wakksre. Bs kpimj gf tank, it bx gur bslenmngn th jfdetagur mt ceei yze Ugnled Lystel t…

书生·浦语大模型实战营-第六课笔记

1.评测追魂夺命三连问 2.主流大拿有话说-评测框架 3.友商最棒儿子最亲&#xff0c;好瓜都是王婆的 4.真枪实弹上战场 为了给平台省点电&#xff0c;我用了自家的电和自家的电脑进行评测。评测的模型也是之前在自己电脑上跑了3轮花费30多个小时的第四课作业微调的法律大模型。s…

智能测径仪 针对设备自身抖动都做了哪些创新加强设计

关键字:测径仪外壳设计,测径仪内部结构,外壳刚性振动,产线共振现象,镜头纯手工擦拭清洗,测径仪智能防抖算法,测径仪多重防抖技术,测径仪防抖技术,测径仪自身防抖&#xff0c; 在生产过程中&#xff0c;被测物不可避免的会发生抖动&#xff0c;测径仪本身也会产生抖动,只是抖动幅…

数据库专题——分库分表

一. 分库分表介绍二. 分库分表实践 一. 分库分表介绍 1.1 分库分表解决了什么问题 先说分库&#xff1a; 《高性能MySQL》中提到了两种数据库扩展方式&#xff1a;垂直扩展和水平扩展。前者意味着买更多性能强悍的硬件&#xff0c;但是总会达到扩展的天花板&#xff0c;且成本…

数字信号处理:傅里叶分析

本文主要参考视频如下&#xff1a; 数字信号处理9-1_线性时不变系统对复指数信号的响应_哔哩哔哩_bilibili 傅里叶分析的主要研究内容如下所示&#xff1a; 注意&#xff0c;计算机中使用的离散傅里叶变换并不是离散时间傅里叶变换&#xff1b; 前四种都是理论上的变换方式&…

mysql 2-21

约束的分类 添加约束 查看表约束 非空约束 唯一性约束 复合的唯一性约束 只要有一个字段不重复&#xff0c;就可以添加成功 主键约束 自增列 mysql 8.0具有持久化&#xff0c;重启服务器会继续自增 外键约束 创建外键 关联必须有唯一性约束&#xff0c;或者是主键 约束等级 …