JVM面试整理--对象的创建和堆

news/2024/5/21 15:07:18/文章来源:https://blog.csdn.net/xu7382/article/details/137611754

文章目录

    • 对象的创建过程是怎样的?
    • 对象在内存中的结构是怎样的(专业的叫法:对象的内存布局)
    • 对象在内存分配时使用的哪种方式(有的地方也称为:分配算法)
    • 知道什么是“指针碰撞”吗?
    • 知道什么是“空闲列表”吗?
    • 内存分配算法是否存在并发问题?是如何解决并发问题的?
    • 请说一说“TLAB”
    • 对象创建好后,如何对其进行定位访问
    • jvm中堆的结构是怎样的?新生代、老年代
    • JVM中老年代和新生代的比例是多少?
    • 说说对象的分配规则。
    • 什么是空间分配担保?

 


对象的创建过程是怎样的?

答:
对象的创建过程大致可分为如下四个步骤:

  • 类加载检查。JVM遇到 new 指令,会去检查能否在常量池中定位到类的符号引用,并且检查该符号引用代表的类是否已经被加载、解析和初始化过。如果没有,则进行类加载过程。
  • 为对象分配内存。内存分配方式可以选择“指针碰撞”或是“空闲列表”。具体选择哪一种,是由堆内存是否规整决定的。
  • 将内存空间初始化为零值(除对象头)。这一步保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用。
  • 为对象进行必要的信息设置。这些信息主要存放在对象头(Object Header)之中。对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息。还有关于对象是否加锁的信息。
    对象头的内容如下:

对象头

助记方法:
1.类是对象的基础,只有加载到jvm的类,才可以创建其对象 -> 类加载检查。
2.对象是需要存储信息的 -> 就需要为其分配内存。
3.对象的信息称为实例变量,实例变量需要赋值才可使用 -> 初始化零值
4.对象头保存了对象的元数据->这些信息是在对象创建时设置的

 


对象在内存中的结构是怎样的(专业的叫法:对象的内存布局)

答:
再次引用前面的图:
对象头
 
对象在堆内存中存储,其内存布局可分为3部分:
对象头、实例数据和对齐填充。

  • 对象头(Object Header)。
    又可再分为两部分:第一部分,官方称为“MarkWord”,存储的是对象自身的运行时数据。如:哈希码(HashCode)、GC分代年龄、锁状态标志、偏向线程ID等;第二部分是“类型指针”(Klass Pointer)。即对象指向它的类元数据的指针,虚拟机可通过其确定该对象是哪个类的实例。如果是数组对象,其对象头还会有一块用于记录数组长度的数据。
     
  • 实例数据(Instance Data)。
    真正存储有效信息的部分,这里主要指对象的实例字段。包含从父类继承的字段信息,相同宽度的字段总是分配在一起。
     
  • 对齐填充(Padding)
    因为对象的大小必须是8字节的整数倍。对象头是8字节的整数倍,但是实例数据则不一定,当其大小不足8字节时,需要对其进行填充,以达到8字节。

下图给出了对象头的空间占用情况:

对象头的空间占用

 


对象在内存分配时使用的哪种方式(有的地方也称为:分配算法)

答:对象在内存分配时,会使用到两种内存分配方式:

  • 指针碰撞
  • 空闲列表

具体使用哪一种内存分配方式,取决于堆内存是否规整。而堆内存是否规整,则决定于垃圾收集器是否带有整理功能(即是否采用了“标记-整理”垃圾收集算法)。

因此,带压缩功能的Serial New等收集器,采用 “指针碰撞” 分配算法。
而像CMS这种基于 Mark-Sweep 算法的收集器,则采用 “空闲列表” 分配算法。

 


知道什么是“指针碰撞”吗?

答:

指针碰撞

一般情况下,JVM的对象都放在堆内存中(发生逃逸分析除外)。
Java虚拟机为新生对象分配内存时。如果Java堆中的内存是绝对规整的,所有被使用过的的内存都被放到一边,空闲的内存放在另外一边,中间以一个指针作为分界点的指示器(如图所示)。那么分配内存所要做的仅仅是把指针向空闲内存方向挪动,挪动的距离正好等于对象的大小,这种内存分配方式就称为“指针碰撞”。

助记点:
1.堆内存需绝对规整(结合图加深理解)。关键字:已使用内存空闲的内存指针分界点的指示器
2.分配内存,即指针向空闲内存方向移动。关键词:向空闲内存的方向移动
3.内存分配方式,称为“指针碰撞”。关键词:内存分配方式

 


知道什么是“空闲列表”吗?

答:
堆内存不规整 (即已使用内存和空闲内存是交错在一起的)时,是不适合使用“指针碰撞”的方式为对象分配内存的。

而对象的内存是需要一整块连续区域的。为了能快速找到合适大小的内存,虚拟机就需要维护一个列表,用于记录哪些内存可用,其大小是多少

当分配内存时,借助于该列表可以很快找到合适的内存。列表中已分配内存的记录需要进行更新(删除还是打标已使用?)。
这种内存分配方式,称为“空闲列表”。

 


内存分配算法是否存在并发问题?是如何解决并发问题的?

答:
内存分配时,不管是使用 “指针碰撞” 还是 “空闲列表” 分配算法,都有可能产生并发问题。

因为可能有多个线程发起了对象创建,从而出现多个线程对同一个内存位置的争抢情况,结果导致某些线程中对象创建失败。

为了解决并发问题,JVM给出了两种方案:

  • CAS + 失败重试
  • TLAB(本地线程分配缓冲)

 


请说一说“TLAB”

答:TLAB是本地线程分配缓冲(Thread Local Allocation Buffer)的缩写。有的地方也翻译为本地线程分配缓存。

它的工作原理:为每一个线程在堆中预先分配一小块内存,称其为TLAB。为线程分配堆内存时,优先从TLAB上分配,当TLAB用完后,再使用同步锁定的方式分配新的TLAB。

虚拟机通过参数 -XX:+/-UseTLAB 决定是否启用TLAB功能。

 


对象创建好后,如何对其进行定位访问

答:对象创建好后,可以通过如下方式对其进行定位访问:

  • 使用句柄
  • 直接指针

使用句柄访问, 将会从堆中划分出一块内存来作为句柄池,reference(栈中的本地变量表) 中存储的是对象的句柄地址,而句柄中包含了对象实例数据指针与对象类型数据指针(二元组)。

使用句柄访问:
在这里插入图片描述

使用句柄访问的好处:

reference 中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要修改。

助记关键词:
句柄池句柄地址-存在本地变量表中句柄是一个二元组<实例数据指针, 类型数据指针>

 
使用直接指针访问,reference 中存储的直接就是对象地址。而对象的头信息中包含对象类型数据的信息(称为对象类型指针) 。

使用直接指针访问:
使用直接指针访问

直接指针访问的好处:

速度更快,节省了一次指针定位的时间开销。

助记关键词:
reference直接指向对象地址对象头中包含类型信息

 


jvm中堆的结构是怎样的?新生代、老年代

答:
Java堆可分为新生代和老年代,新生代和老年代的比例为1:2。这个比例可通过-XX:NewRatio参数进行调整。

新生代又可细分为一块较大的Eden区和两块较小的Survivor区。默认Eden和Survivor大小的比例是8:1。这个比例可以通过 -XX:SurvivorRatio 参数进行调整。

JVM每次只会使用Eden和其中一块Survivor区域来为对象服务,所以总是有一块Survivor区域是空闲的。
所以新生代的实际可用内存空间为9/10的新生代内存空间。

新生代存储的都是新创建的对象、比较小的对象;而老年代存的都是活得久的,或是比较大的对象。所以,老年代占JVM堆内存的比例较大。

下图是新生代和老年代的比例:

新生代和老年代

 


JVM中老年代和新生代的比例是多少?

答:新生代和老年代的默认比例是1:2。这个比例可通过-XX:NewRatio参数进行调整。

注:和堆的内存结构重复,单独拎出来是为了强调该知识点的重要性。

 


说说对象的分配规则。

答:
目前主流的虚拟机都是使用的分代收集算法。对应的内存的分配也是分代分配的。

规则如下:

  • 对象优先分配在Eden区。如果启用了TLAB,则优先在TLAB上分配。当Eden区没有足够空间时,会触发一次Minor GC(YGC)。
  • 大对象(指需要大量连续内存空间的对象,如长字符串和长数组)直接进入老年代。
  • 长期存活的对象进入老年代。对象头的MarkWord中有一个GC分代年龄,默认分代年龄大于15的对象进入老年代。对象首次进入Survivor区后,其对象年龄设为1,然后在Survivor中每熬过一次Minor GC,其对象年龄就加1,直至对象年龄达到阈值,对象直接进入老年代(也称为晋升为老年代)。可通过设置参数-XX:MaxTenuringThreshold修改对象进入老年代的年龄阈值。该规则针对的是Survivor中的对象
  • 动态对象年龄判断。其概念为:如果Survivor中相同年龄的对象的总大小大于Survivor空间的一半,年龄大于等于该年龄的对象,直接进入老年代。注意:这条规则也是针对Survivor中的对象的

    例如:Survivor空间=2M,当中有4个对象:
    对象1:大小-0.5M,年龄-3
    对象2:大小-0.6M,年龄-3
    对象3:大小-0.1M,年龄-2
    对象4:大小-0.2M,年龄-4
     
    根据动态对象年龄判断的规则:对象1+对象2的总大小 > 1M;
    所以,Survivor中年龄大于等于3的对象,都将进入老年代。
    故:对象1、对象2和对象4,都将进入老年代。

  • 空间分配担保。

助记关键词:
Eden区-优先分配大对象Survivor-长期存活的对象Survivor-基于同龄对象占比空间分配担保

参考:
《深入理解Java虚拟机(第2版)》p95、3.6节

 


什么是空间分配担保?

答:
每次在进行Minor GC之前,JVM会检查老年代最大可用连续空间是否大于新生代所有对象的总空间

如果大于,说明Minor GC是安全的,进行Minor GC。

帮助理解 =>(因为Minor GC是对新生代空间的回收,如果其中的对象还需要使用,则需要将其移动到老年代,所以就需要老年代有足够的空间存放这些对象。这里考虑的是最极端的情况,即所有的新生代对象都将进入老年代

如果老年代的最大可用连续空间,放不下所有的新生代对象,那么是否大于历次晋升到老年代的对象的平均大小。如果满足,则进行Minor GC,否则进行Full GC。

担保是由老年代作出的,并且主要发生在第二次判断中。老年代根据历史的经验值,对Minor GC的结果作出担保,保证GC后老年代的最大连续空间可以容纳GC后晋升到老年代的对象大小。

担保依然有失败的可能,因为Minor GC后存活的对象可能会很多,以至于大于老年代的可用连续空间。所以就有了第三个判断。

如果担保失败,则在Minor GC后,会再次触发一次Full GC(如图所示)。

下图演示了“空间分配担保”的流程:

空间分配担保

JDK6 Update24之前的空间分配担保流程如下:

空间分配担保-02

 
 

声明:大部分图片来源自互联网和书籍。

 
 
 


参考:

  • [1] 《深入理解Java虚拟机(第2版)》

  • [2] https://blog.csdn.net/qyj19920704/article/details/123965383

  • [3] https://blog.csdn.net/guorui_java/article/details/137178686

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

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

相关文章

不允许在constexpr函数中进行声明

这是我用pycharm在windows系统下复现sfm深度学习网络(Deep Two-View Structure-from-Motion Revisited&#xff09;遇见的问题&#xff0c;复现时有段代码pytorch扩展cuda/c&#xff0c;pycharm中出现C标准相关的报错如下&#xff1a; 在网上查找很久无果&#xff0c;后面通过…

JVM垃圾收集——垃圾收集器

文章目录 1、垃圾收集器的发展和分类1.1、评估垃圾收集器的性能指标1.1.1、吞吐量1.1.2、停顿时间1.1.3、吞吐量和停顿时间的比较 1.2、垃圾收集器的发展史1.3、垃圾收集器的分类1.4、查看默认的垃圾收集器 2、Serial收集器&#xff1a;串行回收3、ParNew收集器&#xff1a;并行…

【漏洞复现】深澜计费管理系统任意文件读取漏洞

0x01 产品简介 深澜计费管理系统是一套完善的、领先的具有复杂生物型特征的弹性认证计费系统。其主要由以下几个模块组成&#xff1a;AAA认证计费平台、系统运营维护管理平台、用户及策略管理平台、用户自助服务平台、智能客户端模块、消息推送模块以及数据统计模块。该系统为…

Qt Creator实例之图标主题

Chart themes 是 Qt Creator 中图表的主题&#xff0c;它可以用于改变图表的外观和风格&#xff0c;使其更符合你的需求和设计。此示例显示了所有支持的图表类型的不同内置主题的外观。为了给结果一个更和谐的外观&#xff0c;应用程序的背景调色板是根据所选主题定制的。 char…

Mybatis-Plus05(分页插件)

分页插件 MyBatis Plus自带分页插件&#xff0c;只要简单的配置即可实现分页功能 1. 添加配置类 Configuration MapperScan("com.atguigu.mybatisplus.mapper") //可以将主类中的注解移到此处 public class MybatisPlusConfig {Bean public MybatisPlusIntercepto…

功能测试如何到自动化测试,看这篇就够了。

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 本帖不仅给大家介绍自动化测试&#xff0c;更会提供大…

GFS 分布式文件系统

目录​​​​​​​ GlusterFS简介 GlusterFS特点 GlusterFS 术语 GlusterFS 的工作流程 弹性 HASH 算法 GlusterFS的卷类型 分布式卷 条带卷 复制卷 分布式条带卷 分布式复制卷 条带复制卷 分布式条带复制卷 搭建GFS 节点配置 ​编辑 客户端配置 测试 Glust…

提示工程概要

提示工程 1. 两大原则 原则 1&#xff1a;编写清晰具体的说明 使用分隔符 三引号&#xff1a;“”"三个反引号&#xff1a;三个破折号&#xff1a;—尖括号&#xff1a;<>XML标签&#xff1a; 要求结构化输出 HTMLJSONXMLPython字典 检查条件是否满足 检查执行…

13 指针(上)

指针是 C 语言最重要的概念之一&#xff0c;也是最难理解的概念之一。 指针是C语言的精髓&#xff0c;要想掌握C语言就需要深入地了解指针。 指针类型在考研中用得最多的地方&#xff0c;就是和结构体结合起来构造结点(如链表的结点、二叉树的结点等)。 本章专题脉络 1、指针…

二维相位解包理论算法和软件【全文翻译- 掩码(3.4)】

本节我们将研究从质量图中提取掩码的问题。掩码是一个质量图,其像素只有两个值:0 或 1。零值像素标志着质量最低的相位值,这些相位值将被屏蔽、零权重或忽略。第 5 章中的某些 L/ 正则算法需要使用掩码来定义零权重。掩码还可用于某些路径跟踪算法,如第 4.5 节中将要介绍的…

计算机网友将饭卡余额改成100多万

你在学校干过最疯狂的事是什么&#xff1f; 一位学计算机的网友说&#xff0c;他改造过的水卡和饭卡都能无限使用&#xff0c;两年后在食堂刷卡&#xff0c;被食堂阿姨发现余额竟然还剩一百多万&#xff0c;虽然没有赔钱&#xff0c;但是被学校教务处处分了&#xff0c;怎么说…

QT:信号与槽

作业&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

Linux基础篇:Linux第三方软件仓库——可以让Linux变得有趣的软件仓库

Linux第三方软件仓库——可以让Linux变得有趣的软件仓库 一、epel源介绍 EPEL&#xff08;Extra Packages for Enterprise Linux&#xff09;源是一个由Fedora项目组维护的第三方软件仓库&#xff0c;为企业级Linux发行版&#xff08;如Red Hat Enterprise Linux&#xff08;…

Unity之PUN实现多人联机射击游戏的优化(Section 2)

目录 &#x1f3ae;一、准备工作 &#x1f3ae;二、实现手雷投掷动作 &#x1f3ae;三、手雷投掷同步 &#x1f4a4;3.1 photonView.RPC &#x1f3ae;四、同步手雷伤害 这几周都给我布置任务了&#xff0c;最近可忙。现在终于有机会更新了&#xff0c;也谢谢大家的阅读&a…

用dbms_shared_pool.purge清除执行计划

1.Oracle 11g如何清除share pool中某条SQL的执行计划 以前在Oracle 10g数据库上,如果遇到绑定窥探导致执行计划慢的情况,想要清除某条SQL的执行计划,让它硬解析,找了很久都没有找到直接操作share pool的方法&#xff08;总不能alter system flush shared_pool&#xff09;,只能…

自动化测试十大必备(背)面试题!【含答案精讲】

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…

unable to find a medium containing a live file system解决办法!

背景&#xff1a; 用Ventoy制作U盘系统安装盘&#xff0c;只需要把ISO镜像拷进去就可以&#xff0c;可以放多少个镜像取决于U盘的大小&#xff0c;无需重复制作。Ventoy 将U盘的第一个分区默认格式化为exFAT文件系统来存放ISO文件。 但是&#xff0c;今天鲲鹏920平台安装银河…

人工智能前沿成科技竞争新高地

以下文章来源&#xff1a;经济参考报 近日&#xff0c;首届中国具身智能大会&#xff08;CEAI 2024&#xff09;在上海举行。作为人工智能领域的前沿热点&#xff0c;具身智能正逐步走进现实&#xff0c;成为当前全球科技竞争的新高地、未来产业的新赛道、经济发展的新引擎。 “…

二分答案跳石头游戏

步骤&#xff1a; 输入&#xff1a; 用户输入了三个整数&#xff0c;分别表示石头的总长度l&#xff0c;石头的数量n&#xff0c;以及最多可以撤去的石头数量m。 初始化石头位置数组&#xff1a; 创建一个长度为n2的数组arr&#xff0c;用于存储每块石头的位置。数组的第一项…

mysql解锁表及查看表是否被锁

1、查进程&#xff0c;查找被锁表的那个进程的ID show processlist; 2、通过查询结果&#xff0c;找到要杀掉的进程&#xff0c;kill掉锁表的进程ID kill id; 3、查询是否锁表 show OPEN TABLES where In_use > 0; 1.delete------ 是逐行删除速度极慢&#xff0c;不适合…