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

文章目录

    • 对象的创建过程是怎样的?
    • 对象在内存中的结构是怎样的(专业的叫法:对象的内存布局)
    • 对象在内存分配时使用的哪种方式(有的地方也称为:分配算法)
    • 知道什么是“指针碰撞”吗?
    • 知道什么是“空闲列表”吗?
    • 内存分配算法是否存在并发问题?是如何解决并发问题的?
    • 请说一说“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

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

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

相关文章

电商技术揭秘十八:电商平台的云计算与大数据应用小结

电商技术揭秘相关系列文章 电商技术揭秘一&#xff1a;电商架构设计与核心技术 电商技术揭秘二&#xff1a;电商平台推荐系统的实现与优化 电商技术揭秘三&#xff1a;电商平台的支付与结算系统 电商技术揭秘四&#xff1a;电商平台的物流管理系统 电商技术揭秘五&#xf…

【产品】ANET智能通信管理机 物联网网关 电力监控/能耗监测/能源管理系统

产品概述 本系列智能通信管理机是一款采用嵌入式硬件计算机平台&#xff0c;具有多个下行通信接口及一个或者多个上行网络接口&#xff0c;用于将一个目标区域内所有的智能监控/保护装置的通信数据整理汇总后&#xff0c;实时上传主站系统&#xff0c;完成遥信、遥测等能源数据…

遥感图像处理:从畸变消除到专题信息提取

​ ​ ​在遥感技术的应用中&#xff0c;图像处理是不可或缺的关键步骤。从消除各种辐射畸变和几何畸变&#xff0c;到利用增强技术突出景物的光谱和空间特征&#xff0c;再到进一步理解、分析和判别处理后的图像&#xff0c;这一过程为我们呈现了一幅幅更为真实、清晰的…

Elasticsearch:从 ES|QL 到 PHP 对象

作者&#xff1a;来自 Elastic Enrico Zimuel 从 elasticsearch-php v8.13.0 开始&#xff0c;你可以执行 ES|QL 查询并将结果映射到 stdClass 或自定义类的 PHP 对象。 ES|QL ES|QL 是 Elasticsearch 8.11.0 中引入的一种新的 Elasticsearch 查询语言。 目前&#xff0c;它在…

基于GRU实现评论文本情感分析

一、问题建模 在线评论的细粒度情感分析对于深刻理解商家和用户、挖掘用户情感等方面有至关重要的价值&#xff0c;并且在互联网行业有极其广泛的应用&#xff0c;主要用于个性化推荐、智能搜索、产品反馈、业务安全等。此博文&#xff0c;共包含6大类20个细粒度要素的情感倾…

SpringBoot中的Redis的简单使用

在Spring Boot项目中使用Redis作为缓存、会话存储或分布式锁等组件&#xff0c;可以简化开发流程并充分利用Redis的高性能特性。以下是使用Spring Boot整合Redis的详细步骤&#xff1a; 1. 环境准备 确保开发环境中已安装&#xff1a; Java&#xff1a;用于编写和运行Spring…

RISC-V特权架构 - 中断注入

中断注入 1 中断注入的作用2 mip寄存器3 中断注入后的处理过程 本文属于《 RISC-V指令集基础系列教程》之一&#xff0c;欢迎查看其它文章。 1 中断注入的作用 中断注入&#xff0c;就是在M模式下&#xff0c;手动向S模式去产生一个中断。 比如&#xff1a;向mip寄存器的bit5…

✌2024/4/6—力扣—最长公共前缀✌

代码实现&#xff1a; char *longestCommonPrefix(char **strs, int strsSize) {if (strsSize 0) {return "";}for (int i 0; i < strlen(strs[0]); i) { // 列for (int j 1; j < strsSize; j) { // 行if (strs[0][i] ! strs[j][i]) { // 如果比较字符串的第…

三、Mat、Bitmap和Image数据类型之间的转换(OpenCvSharp)

在OpenCV中可以通过ImRead方法读取照片&#xff0c;通过ImShow方法显示照片&#xff1b;但是无法在PictureBox控件中显示 PictureBox控件只能展示Bitmap和Image数据类型图片 为此查阅了网上很多篇博文&#xff0c;将三种数据类型之间的转换进行了归纳整理&#xff0c;感谢网上…

JavaScript进阶6之函数式编程与ES6ESNext规范

函数式编程 柯里化currycurrycompose示例&#xff1a;简化版展开写&#xff1a; debug示例一&#xff1a;示例二&#xff1a; 模板字符串css in js方案 箭头函数问题 生成器 generator应用场景 反射 Reflect 柯里化curry compose是curry的应用 在 lodash/fp underscore ramba …

RTSP/Onvif视频安防监控平台EasyNVR调用接口返回匿名用户名和密码的原因排查

视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种格式。平台拓展性强、支持二次开发与集成&#xff0c;可应用在景区、校园、水利、社区、工地等场…

怎么快速围绕“人、货、场”做零售数据分析?

做零售数据分析多了&#xff0c;不难发现零售数据分析的关键就是“人、货、场”&#xff0c;那么怎么又快又灵活地分析这三个关键点&#xff1f;不妨参考下奥威BI零售数据分析方案。 奥威BI零售数据分析方案是一套吸取大量项目经验&#xff0c;结合零售企业数据分析共性需求打…

【教学类-50-06】20240410“数一数”4类星号图片制作PDF学具

作品展示&#xff1a; 背景需求&#xff1a; 前文遍历四个文件夹&#xff0c;分别将每个文件夹内的10个图片的左上角加入星号&#xff0c;显示难度系数 【教学类-50-05】20240410“数一数”4类图片添加“难度星号”-CSDN博客文章浏览阅读55次&#xff0c;点赞2次&#xff0c;…

xss跨站脚本攻击笔记

1 XSS跨站脚本攻击 1.1 xss跨站脚本攻击介绍 跨站脚本攻击英文全称为(Cross site Script)缩写为CSS&#xff0c;但是为了和层叠样式表(CascadingStyle Sheet)CSS区分开来&#xff0c;所以在安全领域跨站脚本攻击叫做XSS 1.2 xss跨战脚本攻击分类 第一种类型:反射型XSS 反射…

Prime (2021): 2

前言 这个靶机有亿点难,收获很多。打靶的时候&#xff0c;前面很顺&#xff0c;到创建ssh公钥之后就一点不会了。 1 01 arp扫描&#xff0c;发现有一个130&#xff0c;再查看端口 有22&#xff0c;80&#xff0c;129&#xff0c;445&#xff0c;10123 dirb扫描目录 这…

LinuxAndroid: 旋转编码器input输入事件适配(旋转输入)

rk3588s: 旋转编码器input输入事件适配 基于Android 12 kernel-5.10版本 参考文档&#xff1a; https://blog.csdn.net/szembed/article/details/131551950 Linux 输入设备调试详解&#xff08;零基础开发&#xff09;Rotary_Encoder旋转编码器驱动 通用GPIO为例 挂载input输…

废品回收 小程序+APP

用户实名认证、回收员实名认证、后台审核、会员管理、回收员管理、订单管理、提现管理、地图、档案管理。 支持&#xff0c;安卓APP、苹果APP、小程序 流程&#xff1a; 一、用户端下单&#xff0c;地图选择上门位置、填写具体位置、废品名称、预估重量、选择是企业废旧、家…

Netty实现udp服务器

1、TCP与UDP通信协议 网络传输层协议有两种&#xff0c;一种是TCP&#xff0c;另外一种是UDP。 TCP是一种面向连接的协议&#xff0c;提供可靠的数据传输。TCP通过三次握手建立连接&#xff0c;并通过确认和重传机制&#xff0c;保证数据的完整性和可靠性。TCP适用于对数据准…

科技助力输电线安全隐患预警,基于YOLOv5全系列参数【n/s/m/l/x】模型开发构建电力设备场景下输电线安全隐患目标检测预警系统

电力的普及让我们的生活变得更加便利&#xff0c;四通八达的电网连接着生活的方方面面&#xff0c;电力能源主要是依托于庞大复杂的电网电力设备进行传输的&#xff0c;有效地保障电网场景下输电线的安全对于保障我们日常生活所需要的电力有着重要的意义&#xff0c;但是电力设…

Java使用aspose-words实现word文档转pdf

Java使用aspose-words实现word文档转pdf 1.获取转换jar文件并安装到本地maven仓库 aspose-words-15.8.0-jdk16.jar包下载地址&#xff1a;https://zhouquanquan.lanzn.com/b00g257yja 密码:965f 下载aspose-words-15.8.0-jdk16.jar包后&#xff0c;通过maven命令手动安装到本…