jvm中对象创建、内存布局以及访问定位

对象创建

Java语言层面,创建对象通常(例外:复制、反序列化)仅仅是一个new关键字即可,而在虚拟机中,对象(限于普通Java对象,不包括数组和Class对象等)的创建又是怎样一个过程呢?

① Java虚拟机遇到一条字节码new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,那必须先执行相应的类加载过程

类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间实际上便等同于把一块确定大小的内存块从Java堆中划分出来。此时有两种实现情况:

  1. 假如Java堆中内存是绝对规整的被使用过的内存都被放在一边,空闲的内存被放在另一边中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间方向挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”(Bump ThePointer)
  2. 假如Java堆中的内存并不是规整的已被使用的内存和空闲的内存相互交错在一起,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“空闲列表”(Free List)

选择哪种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有空间压缩整理的能力决定。【因此选择哪种分配方式,主要由垃圾收集器决定】

使用Serial、ParNew等带压缩整理过程的收集器时,系统采用的分配算法是指针碰撞,既简单又高效;而当使用CMS基于清除(Sweep)算法的收集器时,理论上就只能采用较为复杂的空闲列表来分配内存。

对象创建在虚拟机中是非常频繁的行为,即使仅仅修改一个指针所指向的位置,在并发情况下也并不是线程安全的,解决这个问题有两种可选方案:

  1. 对分配内存空间的动作进行同步处理——实际上虚拟机是采用CAS配上失败重试的方式保证更新操作的原子性
  2. 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(Thread Local AllocationBuffer,TLAB),哪个线程要分配内存,就在哪个线程的本地缓冲区中分配,只有本地缓冲区用完了,分配新的缓存区时才需要同步锁定虚拟机是否使用TLAB,可以通过-XX:+/-UseTLAB参数来设定

内存分配完成之后,虚拟机必须将分配到的内存空间(但不包括对象头)都初始化为零值,如果使用了TLAB的话,这一项工作也可以提前至TLAB分配时顺便进行。这步操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,使程序能访问到这些字段的数据类型所对应的零值。

Java虚拟机还要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才计算)、对象的GC分代年龄等信息。这些信息存放在对象的对象头(Object Header) 之中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。

此时,从虚拟机的视角来看,一个新的对象已经产生了。从Java程序的视角看来,new指令之后会接着执行()方法,按照程序员的意愿对对象进行初始化,这样一个真正可用的对象才算完全被构造出来。

jvm对象创建过程

对象内存布局

对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)实例数据(Instance Data)对齐填充(Padding)

对象的对象头部分包括两类信息

  1. 第一类是用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32个比特和64个比特,官方称它为“Mark Word”。对象需要存储的运行时数据很多,实际上已经超出了32、64位Bit map结构所能记录的最大限度,Mark Word被设计成一个有着动态定义的数据结构,以便在极小的空间内存储尽量多的数据,根据对象的状态复用自己的存储空间
  2. 另外一部分是类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。

实例数据部分是对象真正存储的有效信息,即在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来。这部分的存储顺序会受到虚拟机分配策略参数(-XX:FieldsAllocationStyle参数)和字段在Java源码中定义顺序的影响。

如果HotSpot虚拟机的+XX:CompactFields参数值为true(默认就为true),那子类之中较窄的变量也允许插入父类变量的空隙之中,以节省出一点点空间

对齐填充,这并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用

HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,即任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8字节的倍数(1倍或者2倍),如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补全。

对象的访问定位

创建对象是为了后续使用该对象,Java程序会通过栈上的reference数据来操作堆上的具体对象。

对象访问方式也是由虚拟机实现而定的,主流的访问方式主要有使用句柄直接指针两种:

  • 句柄:Java堆中将可能会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自具体的地址信息。

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

image-20230918232406004

  • 直接指针访问:reference中存储的直接就是对象地址,如果只是访问对象本身的话,就不需要多一次间接访问的开销。

image-20230918232542071

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

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

相关文章

寄存器介绍

目录 寄存器的概念 寄存器工作原理 寄存器的状态 查看寄存器信息 寄存器复位 大空间寄存器复位 寄存器的概念 寄存器是计算机中一种临时存储数据的硬件设备,通常是高速缓存的一部分,用于存储、读取和操作计算机内部的数据。它们是计算机中最快的存…

小米华为,化干戈为玉帛!

近日来,手机圈又掀起了各大厂家推出新品的高潮。首先是华为Mate60的推出,其自研的麒麟9000S芯片瞬间点燃了国内手机市场,得到了国内甚至国外业界人士的认可和好评。 而近日网上盛传的小米创始人雷军的“愿意加入华为技术生态圈”的邀请&…

AtCoder ARC106 E Hall 定理 + 二分 + 容斥原理 + 高维前后缀和

题意 传送门 AtCoder ARC106 E Medals 题解 问题可以转化为每一天与职员之间的匹配问题,思路与 AtCoder ABC320 G Slot Strategy 2 (Hard) 类似。但二分图规模过大,直接求解最大匹配显然难以胜任。 根据 Hall 定理,若二分图一侧点集 S S…

JS操作字符串方法学习系列(4)-每天学习10个方法

目录 **字符串编码 (encodeURIComponent 和 decodeURIComponent)**:**字符串转换为日期 (Date Parsing)**:**字符串模板引擎 (Template Engines)**:**字符串替换所有匹配项 (replaceAll)**:**字符串分隔并限制 (String.prototype.split)**:**字符串转义字符 (Escape Characters…

Redis缓存实现及其常见问题解决方案

随着互联网技术的发展,数据处理的速度和效率成为了衡量一个系统性能的重要指标。在众多的数据处理技术中,缓存技术以其出色的性能优化效果,成为了不可或缺的一环。而在众多的缓存技术中,Redis 以其出色的性能和丰富的功能&#xf…

JDK jps命令复习

之前写过jdk命令工具的博文,下面复习jps命令; jps 是 Java Process Status Tool 的简称,它的作用是为了列出所有正在运行中的 Java 虚拟机进程和相关信息; jps 命令参数 -q 只输出进程 ID,省略主类的名称 -m 输出虚拟机进程启动时传递…

C#使用OpenCv(OpenCVSharp)图像轮廓凸包检测与绘制

本文实例演示C#语言中如何使用OpenCv(OpenCVSharp)对图像凸包轮廓检测与绘制。 找轮廓 public static void FindContours(InputArray image, out Point[][] contours, out HierarchyIndex[] hierarchy, RetrievalModes mode, ContourApproximationModes method, Point? of…

python经典百题之求前!的和

题目:求12!3!…20!的和 方法一: 使用for循环和阶乘函数计算每项的值,再将每项的值累加起来。 def factorial(n):if n 0:return 1else:return n * factorial(n-1)sum 0 for i in range(1, 21):sum factorial(i) * iprint(sum)优点&#…

Vue-DPlayer详细使用(包含遇到坑)

Vue-DPlayer:一个优秀的视频播放器组件 Vue-DPlayer是一个易于使用、高性能的基于Vue.js的视频播放器组件。如果你需要在你的Vue.js应用程序中实现视频播放功能,那么Vue-DPlayer就是一个很好的选择。在下面的文章中,我们将从以下四个方面对V…

AG35学习笔记(一):debug串口抓取模组log、debug串口测试AT指令、echo命令通过串口发送16进制数据

目录 一、概述二、抓取模组log2.1 硬件接口2.2 用户登录2.3 相关指令 三、测试AT指令3.1 查看端口3.2 进入模式 四、串口发16进制echo使用 一、概述 二、抓取模组log 在之前记录了通过USB,使用移远工具Qwinlog来抓取log(3.3 抓取模组log)。…

【Java】第一个Servlet程序

第一个Servlet程序 创建项目引入依赖手动创建必要的目录/文件编写代码打包程序部署验证程序是否正常工作 创建项目 选中maven 创建好项目后,观察左侧项目结构 引入依赖 当权代码需要使用servlet开发,而Java标准库中并没有servlet,此时就需要让maven能够把servlet的依赖获取…

子网的划分

强化计算机网络发现王道没有这一块的内容,导致做题稀里糊涂。于是个人调研补充。 子网划分是将一个大型IP网络划分成更小的子网,以实现更有效的网络管理和资源分配。 原因: 提高网络性能:子网划分可以减少广播域的大小&#xff…

成集云 | 用友NC集成旺店通ERP(旺店通主管库存)| 解决方案

源系统成集云目标系统 方案介绍 用友NC是用友NC产品的全新系列,是面向集团企业的世界级高端管理软件。它以“全球化集团管控、行业化解决方案、全程化电子商务、平台化应用集成”的管理业务理念而设计,采用J2EE架构和先进开放的集团级开发平台…

bootstrap柵格

.col-xs- 超小屏幕 手机 (<768px) .col-sm- 小屏幕 平板 (≥768px) .col-md- 中等屏幕 桌面显示器 (≥992px) .col-lg- 大屏幕 大桌面显示器 (≥1200px) 分为12个格子 -后面的1代表占12分子1也就是一份 1.中等屏幕 <div class"container-fluid a">&l…

Autojs 小游戏实践-潮玩宇宙开扭蛋

概述 最近在玩潮流宇宙&#xff0c;里面有扭蛋兔的一个玩法&#xff0c;开始有很多蛋&#xff0c;需要我们一个个点开&#xff0c;然后根据装备品质替换分解&#xff0c;潮流提供了自动开扭蛋功能&#xff0c;但是开到品质比自己装备好的时候回暂停&#xff0c;由于个人懒得看…

在Kubernetes上安装和配置Istio:逐步指南,展示如何在Kubernetes集群中安装和配置Istio服务网格

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

java字符串训练与学习

package com.itheima;import java.util.StringTokenizer;public class 字符串训练学习 {public static void main(String[] args) {String s new String("HelloWorld");System.out.println(s);System.out.println(s.length());//创建字符串//String s new String(&…

掌握这三大要素,轻松写出爆款软文

随着网络的快速发展&#xff0c;软文营销的趋势也在不断变化&#xff0c;做软文看似简单&#xff0c;但是想要做出成绩&#xff0c;真正吸引用户其实是有一定难度的&#xff0c;也有不少企业向媒介盒子咨询软文写作的相关话题&#xff0c;今天就让媒介盒子告诉大家&#xff0c;…

Linux查找文件内容的命令

在Linux中&#xff0c;您可以使用以下命令来查找文件内容&#xff1a; grep命令&#xff1a; grep命令用于在文件中搜索指定的文本模式&#xff0c;并将包含匹配的行打印出来。语法如下&#xff1a; grep "要查找的文本" 文件名例如&#xff0c;要在名为example.txt的…

【深度学习 | LSTM】解开LSTM的秘密:门控机制如何控制信息流

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…