JVM HotSpot 虚拟机: 对象的创建, 内存布局和访问定位

目录

前言

对象的创建

对象的内存布局

对象的访问定位  


前言

        了解JVM的内存区域划分之后, 也大致了解了java程序的内存分布模型, 也了解它里面的内存区域里面的类型和各个类型的作用, 接下来我们进一步从对象创建到访问的角度, 来看看这些内存区域之间是怎么关联起来的. 


对象的创建

         对象的创建在java语言中最直接的体现就是new这个关键字, 虚拟机在遇到一个new指令(这个指令是JVM内部指令集的一部分, 直到JVM如何对对象分配内存并初始化 )的时候, 首先会去检查这个指令的参数(例如类名, 你要实例化的是哪一个类的)是否能在常量池中定位到一个符号引用.

        这些类的信息一般都存储在常量池中, 常量池是方法区的一部分, 用于存储各种字面量和符号引用, 常量池在编译的时候就已经确定了. 在运行时,JVM会将这些符号引用解析为直接引用,即指向内存中实际的类或字段等的指针或偏移量. 

什么符号引用, 什么是直接引用? 

符号引用用于表示一个类、接口、字段或方法的引用

在java语言层面,  一个类被编译之后就会生成字节码文件, 也就是Class文件, class文件中有着类文件的常量池, 在这个类文件被加载的时候, 对应的常量池也会被加载到虚拟机运行时常量池中去. 

        简而言之就是JVM会去检查new指令对应的类的Class文件是否被加载, 如果被加载, 那么就一定可以在运行时常量池中找到对应的类符号引用, 如果找不到就进行类的加载过程. 

        例如当执行到new MyClass()时,JVM会检查MyClass是否已经被加载到内存中。如果没有,JVM会触发类加载过程,将MyClass的字节码加载到内存中,并创建一个java.lang.Class对象来表示这个类。在这个过程中,MyClass的符号引用(如类的全限定名)会被解析为直接引用(如指向内存中Class对象的引用)

        在类加载校验通过之后, 就是为对象分配内存的时候, 创建对象所需的内存其实是在类加载之后就可以完全确定的.

        接下来的问题就是如何分配内存, 有两种方式: 

  • 指针碰撞
  • 内存块列表

        指针碰撞其实就是假设java内存是绝对规整的, 例如将一个内存划分为两块, 一块是已经被使用的内存区域, 一块是空闲的内存区域 他们之间有一个指针来标记当前已被使用的内存的地址, 如下: 

        这个指针也被称为分界点指针

        另外一种就是内存块列表: 

        java虚拟机的堆内存, 一般不是规整的, 那么空闲的内存和已使用内存就会交错在一起, 这个时候使用分界点指针就没什么意义, 此时虚拟机就必须维护一个表, 这个表将java的堆内存划分为很多个内存块, 表里面的指针分别指向对应的内存块, 并且记录了那些内存是可用的, 分配的时候, 从内存块中找出一个拥有足够大的内存空间的给实例对象即可.

        具体采用那种方式, 需要看虚拟机的具体实现.  比如有的虚拟机是内存规整的, 就可以使用指针碰撞的方法. 而是否规整又取决于内存的回收机制, 如果一个垃圾回收器可以将带有内存碎片的空间给整理成上述的规整形态, 就可以使用指针碰撞的形式. 

        上述只是对象的内存分配, 还有一个问题就是在分配完成内存之后, 修改指针引用的时候会出现并发问题, 例如, 给引用A创建好一个对象之后, 需要将对象的地址付给A的指针, 但是在还没赋值好的时候, 另外一个对象使用了这个A的指针, 就会出现问题. 

        针对这个问题, JVM采用了CAS + 失败重试的方法保证 分配和更新引用 这两个操作的原子性, 另外一种做法就是使用线程分配缓冲, 一个线程只能访问自己本地缓存, 只有本地缓冲区用完了, 才可以使用锁区同步申请缓存空间.

        内存分配完之后, 为分配好的内存的对象进行初始化零值操作, 使程序能访问到这些字段的数据类型所对应的零值

        接下来就是对象头的设置. 例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才计算)、对象的GC分代年龄等信息

        这些东西都完成之后, 剩下的就是根据程序员自己的代码逻辑进行初始化操作, 也就是调用构造方法, 即Class文件中的<init>()方法. 这个方法只会执行一次, 按照程序员的意愿对对象进行初始化,这样一个真正可用的对象才算完全被构造出来

对象的内存布局

         在HotSpot中, 对象在内存中的存储布局可以划分为3个: 

  • 对象头
  • 实例数据
  • 对齐填充

        对象的对象头部分包括两类信息, 第一类是用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32个比特和64个比特,官方称它为“Mark Word”. 

        对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例, 如果对象是一个Java数组,那在对象头中还必须有一块用于
记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是如果数组的长度是不确定的,将无法通过元数据中的信息推断出数组的大小.

        接下来就是实例数据, 是对象真正存储的有效信息,即我们在程序代码里面所定义的各种类型的字段内容,无论是从父类继承下来的,还是在子类中定义的字段都必须记录起来

        第三部分就是内存对齐: 这并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是任何对象的大小都必须是8字节的整数倍。对象头部分已经被精心设计成正好是8字节的倍数(1倍或者2倍),因此,如果对象实例数据部分没有对齐的话,就需要通过对齐填充来补


对象的访问定位  

        接下来你应该需要了解 一个对象存储在堆区该怎么访问? 我们之前提到过, 一个对象的实例创建并调用init初始化之后, 就是一个完全体的对象了, 然后这个对象会被赋值给java虚拟机栈中的一个引用变量, 然后你可以通过这个变量去访问他

        这个引用变量也被称为reference数据, 通过它来操作堆中的数据, 但是由于它只是规定了它指向一个内存对象, 但是没有明确的指明该如何指定, 所以说不同的场景下的定位方法, 有着不同的性能区别. 

        一般有下面这两种: 

  • 句柄
  • 直接引用

        如下图: 

        句柄引用其实就是利用了java内存布局中对象头和实例数据的存储可以在不同的运行时区域, 例如, java的对象头可以存储在方法区, 实例数据则存放在堆区. 然后在堆区中生成一个句柄池子, 池子中有很多句柄对象, 一个句柄对象可以被一个reference类型数据给引用, 然后一个句柄对象就是表示一个完整的对象信息, 里面包括对实例数据和对象头数据的引用. 

句柄引用
句柄引用

        下面这一种就是最直接的做法, reference指向的就是java内存中对象的地址. 然后对象的类型数据则是存放的指针, 真正的类型数据存放在方法区中.  

直接引用

区别? 

  • 使用句柄池, 就需要单独在内存中开辟句柄池空间 , reference存储的使句柄池, 访问句柄池中的句柄对象之后, 还需要通过句柄对象中的指针, 再寻找一次真正的实例对象数据和对象类型数据. 相当于多了一次寻找的开销, 最大的优势就是句柄池是稳定的, 对象无论怎么修改, 只要保持和句柄池中的数据指向一致即可,  而对于reference来说, 对象内存地址的修改是透明的(例如GC的情况下 ,  对象的地址可能就会发生变化.), reference不需要改变句柄对象的指向.
  • 使用指针访问就直接很多, reference指向的既是对象, 可以直接访问其实例数据.  免去了一次寻找对象实例数据的开销, 由于对象访问在Java中非常频繁,因此这类开销积少成多也是一项极为可观的执行成本

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

2023高教社杯全国大学生数学建模竞赛C题 Python代码演示

目录 问题一1.1 蔬菜类商品不同品类或不同单品之间可能存在一定的关联关系&#xff0c;请分析蔬菜各品类及单品销售量的分布规律及相互关系。数据预处理数据合并提取年、月、日信息对蔬菜的各品类按月求销量均值 季节性时间序列分解STL分解加法分解乘法分解 ARIMALSTM import p…

什么是代理IP_如何建立代理IP池?

什么是代理IP_如何建立代理IP池&#xff1f; 1. 概述1.1 什么是代理IP&#xff1f;1.2 代理IP的工作原理1.3 爬虫的应用场景1.3.1 搜索引擎&#xff0c;最大的爬虫1.3.2 数据采集&#xff0c;市场分析利器1.3.3 舆情监控&#xff0c;品牌营销手段1.3.4 价格监测&#xff0c;全网…

时序差分法

一、时序差分法 时序差分是一种用来估计一个策略的价值函数的方法&#xff0c;它结合了蒙特卡洛和动态规划算法的思想。时序差分方法和蒙特卡洛的相似之处在于可以从样本数据中学习&#xff0c;不需要事先知道环境&#xff1b;和动态 规划的相似之处在于根据贝尔曼方程的思想&…

外网(公网)访问VMware workstation 虚拟机内web网站的配置方法---端口转发总是不成功的原因

问题背景&#xff1a;客户提供的服务器操作系统配置web程序时&#xff0c;总是显示莫名其妙的问题&#xff0c;发现是高版本操作系统的.net库已经对低版本.net库进行了大范围修订&#xff0c;导致在安全检测上、软件代码规范上更加苛刻&#xff0c;最终导致部署不成功。于是想到…

【C++】入门基础(下)

Hi&#xff01;很高兴见到你~ 目录 7、引用 7.3 引用的使用&#xff08;实例&#xff09; 7.4 const引用 【第一分点】 【第二分点1】 【第二分点2】 7.5 指针和引用的关系&#xff08;面试点&#xff09; 8、inline 9、nullptr Relaxing Time&#xff01; ———…

基于VUE的老年颐养中心系统的设计与实现计算机毕业论文

根据联合国的预测&#xff0c;2000-2050年将是我国人口年龄结构急剧老化的阶段&#xff0c;老化过程大致也可分为三个阶段&#xff1a;第一阶段&#xff0c;65岁及以上人口比例从2000年的6.97%上升到2020年的11.7%&#xff0c;20年时间仅上升4.63个百分点。第二阶段为2020-2040…

蓝桥杯省赛真题——大臣的旅费

输入样例&#xff1a; 5 1 2 2 1 3 1 2 4 5 2 5 4 输出样例&#xff1a; 135分析&#xff1a; 本题实际上要求我们去求在图中最远两点之间的距离&#xff0c;也就是树的直径 我们先从某一个点出发&#xff0c;到达离其最远的点&#xff0c;然后再重复操作一次即可 #inclu…

钢轨缺陷检测-目标检测数据集(包括VOC格式、YOLO格式)

钢轨缺陷检测-目标检测数据集&#xff08;包括VOC格式、YOLO格式&#xff09; 数据集&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1h7Dc0MiiRgtd7524cBUOFQ?pwdfr9y 提取码&#xff1a;fr9y 数据集信息介绍&#xff1a; 共有 1493 张图像和一一对应的标注文件 标…

【二叉树进阶】二叉搜索树

目录 1. 二叉搜索树概念 2. 二叉搜索树的实现 2.1 创建二叉搜索树节点 2.2 创建实现二叉搜索树 2.3 二叉搜索树的查找 2.4 二叉搜索树的插入 2.5 二叉搜索树的删除 2.6 中序遍历 2.7 完整代码加测试 3. 二叉搜索树的应用 3.1 K模型&#xff1a; 3.2 KV模型&#xf…

数据技术革命来袭!从仓库到飞轮,企业数字化的终极进化!

文章目录 数据仓库&#xff1a;信息化的基石数据中台&#xff1a;数字化转型的加速器数据飞轮&#xff1a;智能化的新纪元技术演进的驱动力 自20世纪80年代末数据仓库问世以来&#xff0c;它迅速成为企业数据管理的核心。作为一名大数据工程师&#xff0c;我深刻体会到数据仓库…

k8s使用本地docker私服启动自制的flink集群

目标&#xff1a;使用本地flink环境自制flink镜像包上传到本地的私服&#xff0c;然后k8s使用本地的私服拉取镜像启动Flink集群 1、将本地的flink软件包打包成Docker镜像 从官网下载flink-1.13.6的安装包&#xff0c;修改其中的flink-conf.yaml&#xff0c;修改下面几项配置 …

Mistral AI再创新高,Pixtral 12B多模态模型强势来袭

前沿科技速递&#x1f680; 近日&#xff0c;Mistral AI 发布了其首款多模态大模型——Pixtral 12B。作为一款具有语言与视觉处理能力的模型&#xff0c;Pixtral 12B 支持高达10241024像素的图像&#xff0c;具备强大的文本生成、图像理解与生成能力&#xff0c;能够处理复杂的…

热成像目标检测数据集

热成像目标检测数据集 V2 版本 项目背景 热成像技术因其在安防监控、夜间巡逻、消防救援等领域的独特优势而受到重视。本数据集旨在提供高质量的热成像图像及其对应的可见光图像&#xff0c;支持热成像目标检测的研究与应用。 数据集概述 名称&#xff1a;热成像目标检测数据…

Kafka日志索引详解与常见问题分析

目录 一、Kafka的Log日志梳理 1、Topic下的消息是如何存储的&#xff1f; 1. log文件追加记录所有消息 2. index和timeindex加速读取log消息日志 2、文件清理机制 1. 如何判断哪些日志文件过期了 2. 过期的日志文件如何处理 3、Kafka的文件高效读写机制 1. Kafka的文件…

图神经网络模型扩展(5)--2

1.图的无监督学习 在数据爆炸的时代&#xff0c;大部分数据都是没有标签的。为了将它们应用到深度学习模型上&#xff0c;需要大量的人力来标注数据&#xff0c;例如我们熟知的人脸识别项目&#xff0c;如果想取得更好的识别效果&#xff0c;则一定需要大量人工标注的人脸数据。…

Android MediaPlayer + GLSurfaceView 播放视频

Android使用OpenGL 播放视频 概述TextureView的优缺点OpenGL的优缺点 实现复杂图形效果的场景参考 概述 在Android开发中&#xff0c;使用OpenGL ES来渲染视频是一种常见的需求&#xff0c;尤其是在需要实现自定义的视频播放界面或者视频特效时。结合MediaPlayer&#xff0c;我…

【论文阅读】BC-Z: Zero-Shot Task Generalization with Robotic Imitation Learning

Abstract 在这篇论文中&#xff0c;我们研究了使基于视觉的机器人操纵系统能够泛化到新任务的问题&#xff0c;这是机器人学习中的一个长期挑战。我们从模仿学习的角度来应对这一挑战&#xff0c;旨在研究如何扩展和扩大收集的数据来促进这种泛化。为此&#xff0c;我们开发了…

数据库之索引<保姆级文章>

目录&#xff1a; 一. 什么是索引 二. 索引应该选择哪种数据结构 三. MySQL中的页 四. 索引分类及使用 一. 什么是索引&#xff1a; 1. MySQL的索引是⼀种数据结构&#xff0c;它可以帮助数据库高效地查询、更新数据表中的数据。 索引通过 ⼀定的规则排列数据表中的记录&#x…

F28335 时钟及控制系统

1 F28335 系统时钟来源 1.1 振荡器OSC与锁相环PLL 时钟信号对于DSP来说是非常重要的,它为DSP工作提供一个稳定的机器周期从而使系统能够正常运行。时钟系统犹如人的心脏,一旦有问题整个系统就崩溃。DSP 属于数字信号处理器, 它正常工作也必须为其提供时钟信号。那么这个时钟…

【例题】lanqiao3225 宝藏排序Ⅰ

这里的n的范围可以使用冒泡排序、选择排序和插入排序等算法。 冒泡排序 nint(input()) alist(map(int,input().split()))def pop_sort(a):for i in range(n):for j in range(n-i-1):if a[j]>a[j1]:a[j],a[j1]a[j1],a[j] pop_sort(a) print( .join(map(str,a)))选择排序 n…