百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT精选 > 正文

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

ccwork 2025-03-14 15:30 11 浏览

对象的创建

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

类加载检查

  • HotSpot虚拟机遇到一条new指令,会先检查能否在常量池中定位到这个类的符号引用,检查这个类是否类加载过
    • 没有类加载过就去类加载
    • 类加载过就进行下一步分配内存


分配内存

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

分配内存方式

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

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

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

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

分配内存流程

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

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

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

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

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

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

TLAB 本地线程分配缓存

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

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

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

在并发情况下分配内存是不安全的(正在给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)
  • Mark Word:用于存储该对象自身运行时数据(该对象的哈希码信息,GC信息:分代年龄,锁信息:状态标志等)
  • 类型指针(对象指向它类型元数据的指针):HotSpot通过类型指针确定该对象是哪个类的实例 (如果该对象是数组,对象头中还必须记录数组的长度)
  • 类型指针默认是压缩指针,内存超过32G时为了寻址就不能采用压缩指针了
  • 实例数据是对象真正存储的有效信息
  • 记录从父类中继承的字段和该类中定义的字段
  • 父类的字段会出现在子类字段之前,默认子类较小的字段可以插入父类字段间的空隙以此来节约空间(+XX:CompactFields)
  • 对齐填充
  • HotSpot要求对象起始地址必须是8字节整倍数
  • 所以任何对象的大小都必须是8字节的整倍,如果对象实例数据部分未到达8字节就会通过对齐填充进行补全

分析对象占用字节

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

导入JOL依赖

 
         
             org.openjdk.jol
             jol-core
             0.12
         

mark word : 8 byte

类型指针: 4 byte

对齐填充 12->16 byte

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

mark word:8 byte

类型指针: 4 byte

数组长度: 4 byte

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

对齐填充: 36 -> 40 byte

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

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

栈-堆-方法区结构图

对象的访问定位

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

访问方式

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

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

  • 句柄访问

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

  • 直接指针访问

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

优点: 访问速度快

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

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

相关推荐

二十三、Java类与对象简介(java第十一章类和对象)

在Java编程语言中,类(Class)和对象(Object)是面向对象编程(OOP)的核心概念。描述类类是Java程序的基本组成单元,是对象的模板。类定义了对象的属性和方法。属性是对象的状态信息,而方...

设计模式-结构型-代理模式(proxy)

1.概念需要给对象提供一个代理以控制对该对象的访问,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介;根据代理类生成时机不同,分为静态代理和动态代理;静态代理代理类在编...

深度解析设计模式七大原则之——里氏替换原则

临近端午节,各位读者,你们假期行程安排好了吗?“菜鸟”已经做好决定了,谁都不能阻拦(产品经理也不行),“菜鸟”要好好在家休息三天。最近实在是太累了,一直在疯狂的加班。好了好了言归正传,开始我们的正文。...

Java代理模式详解:智能中介的编程艺术

一、生活场景中的代理思维想象您要租房子,但不想直接与房东打交道,这时房产中介就发挥作用了:1.中介帮您筛选房源(访问控制)2.签约前验证房东资质(预处理)3.协助办理合同手续(功能增强)4.处...

哪个创意最能打动你? 为你欣赏的“创意之星”投一票

这一期的《超级课堂·暑期特别活动》将评出5位“创意之星”,获得价值2000元的奖品。本期我们选登了部分中小学生在昙华林留下的创意作品,欢迎为最能打动你的作品投上一票。大众评审目前采取微信投票:扫描二维...

Netty基础—6.Netty实现RPC服务(netty reactor)

大纲1.RPC的相关概念2.RPC服务调用端动态代理实现3.Netty客户端之RPC远程调用过程分析4.RPC网络通信中的编码解码器5.Netty服务端之RPC服务提供端的处理6.RPC服务调用端实现...

静态代理和动态代理(静态代理和动态代理的优缺点)

1.什么是代理很多人肯定听过和看到过飞机票代理点,火车票代理点。那这些代理点干得事情就是帮航空公司,火车站出售火车票的工作。它们算是一个中间商。实际的服务不是由它们提供。而是由真正的服务商提供。通过这...

Java反射机制与Spring动态代理深度解析

一、Java反射机制原理剖析1.1反射的本质与实现基础Java反射(Reflection)是Java语言的核心特性,允许程序在运行时:动态加载类获取类结构元数据操作类属性和方法关键技术支撑:java...

Java 代理模式详解(java代理原理)

1.代理模式代理模式是一种比较好理解的设计模式。简单来说就是我们使用代理对象来代替对真实对象(realobject)的访问,这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象...

SpringBoot全局异常处理:如何优雅应对多系统多格式错误响应需求

SpringBoot全局异常处理:如何优雅应对多系统多格式错误响应需求引言部分在微服务架构中,你是否曾为处理不同外部系统的异常响应而头痛?A系统要求返回JSON格式的:{code:1001,mes...

3分钟吃透代理技术!(代理一般都是怎么做)

最近有学员问了我一些问题,什么是代理,又该在什么地方使用。结合之前的讨论,这篇文章我们一起细致的讲解一下关于代理的一些问题。在Java中,代理通常分为两类:静态代理动态代理两者技术实现是不一样的,...

苏州网络维护 | 学习网络维护,从哪入手

我们想要学习网络维护,从哪入手呢?先带大家了解下网络维护1.培养基础知识:建立对计算机网络基本原理的理解。学习计算机网络的基础概念,如IP地址、子网掩码、路由器、交换机、协议等。2.学习网络技术:深入...

CAD如何快速一键编号?(cad如何一次性全部编号)

cad一键自动编号。·第一步,在命令行数abh空格。·第二步,打开自动编号对话框,选择用默认的图言编号,编号文字的高度根据图纸的大小设置零点八。当然如果图纸很大,设置比如十一百的有可能数字编号,这点很...

职场新人必知的10个高效工作法,助你快速升职加薪

初入职场,面对繁杂的工作任务和陌生的职场环境,如何才能快速适应并脱颖而出?以下是10个高效工作法,帮助职场新人提升工作效率,快速实现升职加薪的目标。---1.制定每日工作计划-推荐理由:每天开始...

《魔导英雄传说》新手攻略,快速升级,礼包码,最强阵容排列

《魔导英雄传说》新手攻略一、武将培养指南英雄选择与培养:英雄品质分为SSR、SR、A,优先培养SSR英雄,如张飞、孙尚香等核心英雄阵营搭配:同阵营上阵英雄越多,战力加成越高,建议优先培养同一阵营的英雄...