JVM-对象创建与内存分配机制深度剖析 3

 

JVM对象创建过程详解

类加载检查 

  • 虚拟机遇到一条new指令时,首先将去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个 符号引用代表的类是否已被加载、解析和初始化过。
  • 如果没有,那必须先执行相应的类加载过程。 new指令对应到语言层面上讲是,new关键词、对象克隆、对象序列化等。

分配内存 

  • 在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需内存的大小在类 加载完成后便可完全确定,为 对象分配空间的任务等同于把 一块确定大小的内存从Java堆中划分出来。 这个步骤有两个问题: 
    • 1.如何划分内存。
    •  2.在并发情况下, 可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存的 情况。
  • 划分内存的方法: 
    • “指针碰撞”(Bump the Pointer)(默认用指针碰撞) 
      • 如果Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点 的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离。 
    • “空闲列表”(Free List) 
      • 如果Java堆中的内存并不是规整的,已使用的内存和空 闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟 机就必须维护一个列表,记 录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例, 并更新列表上的记录。
  • 解决并发问题的方法: CAS(compare and swap) 
    • 虚拟机采用CAS配上失败重试的方式保证更新操作的原子性来对分配内存空间的动作进行同步处理。 
    • 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)
      • 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存。通过­XX:+/­ UseTLAB参数来设定虚拟机是否使用TLAB(JVM会默认开启­XX:+UseTLAB),­XX:TLABSize 指定TLAB大小。

初始零值

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

设置对象头 

  • 初始化零值之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头Object Header之中。
  •  在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:
    • 对象头(Header)、 
    • 实例数据(Instance Data)
    • 对齐填充(Padding)。
  •  HotSpot虚拟机的对象头包括两部分信息,
    • 第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时 间戳等。
    • 对象头的另外一部分 是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

执行<init>方法 

  • 执行<init>方法,即对象按照程序员的意愿进行初始化。对应到语言层面上讲,就是为属性赋值(注意,这与上面的赋 零值不同,这是由程序员赋的值),和执行构造方法。

对象头与指针压缩

对象大小查看

  • 对象大小可以用jol­core包查看

什么是java对象的指针压缩? 

  • jdk1.6 update14开始,在64bit操作系统中,JVM支持指针压缩
  •  jvm配置参数:UseCompressedOops,compressed­­压缩、oop(ordinary object pointer)­­对象指针 
  • 启用指针压缩:­XX:+UseCompressedOops(默认开启),禁止指针压缩:­XX:­UseCompressedOops

为什么要进行指针压缩?

  • 在64位平台的HotSpot中使用32位指针,内存使用会多出1.5倍左右,使用较大指针在主内存和缓存之间移动数据, 占用较大宽带,同时GC也会承受较大压力
  • 为了减少64位平台下内存的消耗,启用指针压缩功能 
  • 在jvm中,32位地址最大支持4G内存(2的32次方),可以通过对对象指针的压缩编码、解码方式进行优化,使得jvm 只用32位地址就可以支持更大的内存配置(小于等于32G) 
  • 堆内存小于4G时,不需要启用指针压缩,jvm会直接去除高32位地址,即使用低虚拟地址空间 
  • 堆内存大于32G时,压缩指针会失效,会强制使用64位(即8字节)来对java对象寻址,这就会出现1的问题,所以堆内 存不要大于32G为好。
对象栈上分配
分配流程
对象栈上分配
  • 通过JVM内存分配可知JAVA中的对象都是在堆上进行分配。
  • 当对象没有被引用的时候,需要依靠GC进行回收内 存,如果对象数量较多的时候,会给GC带来较大压力,也间接影响了应用的性能。
  • 为了减少临时对象在堆内分配的数量?
    • JVM通过逃逸分析确定该对象会不会被外部访问。如果不会逃逸可以将该对象在栈上分配内存,这样该对象所占用的 内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力。
  •  对象逃逸分析
    • 就是分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用,例如作为调用参 数传递到其他地方中。
    • 开启逃逸分析参数:
      • -XX:+DoEscapeAnalysis,使其通过标量替换优先分配在栈上(栈上分配),JDK7之后默认开启逃逸分析,如果要关闭使用参数(-XX:-DoEscapeAnalysis)
    • 如下示例:
      • 很显然test1方法中的user对象被返回了,这个对象的作用域范围不确定,test2方法中的user对象我们可以确定当方法结 束这个对象就可以认为是无效对象了,对于这样的对象我们其实可以将其分配在栈内存里,让其在方法结束时跟随栈内 存一起被回收掉。            
  • 标量替换
    • 通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是将该 对象成员变量分解若干个被这个方法使用的成员变量所代替,这些代替的成员变量在栈帧或寄存器上分配空间,这样就 不会因为没有一大块连续空间导致对象内存不够分配。
    • 开启标量替换参数
      • -XX:+EliminateAllocations,JDK7之后默认 开启。
  •  标量与聚合量:
    • 标量即不可被进一步分解的量,而JAVA的基本数据类型就是标量(如:int,long等基本数据类型以及 reference类型等)
    • 标量的对立就是可以被进一步分解的量,而这种量称之为聚合量。而在JAVA中对象就是可以被进一 步分解的聚合量。
  • 结论:栈上分配依赖于逃逸分析和标量替换

对象在Eden区分配

对象分配规则

  • 大多数情况下,对象在新生代中 Eden 区分配。
  • 大量的对象被分配在eden区,eden区满了后会触发minor gc,可能会有99%以上的对象成为垃圾被回收掉,剩余存活的对象会被挪到为空的那块survivor区。
  • 下一次eden区满了后又会触发minor gc,把eden区和survivor区垃圾对象回收
  • 把剩余存活的对象一次性挪动到另外一块为空的survivor区,
  • 因为新生代的对象都是朝生夕死的,存活时间很短,所以JVM默认的8:1:1的比例是很合适的,让eden区尽量的大,survivor区够用即可。
  • Eden与Survivor区默认8:1:1
    • JVM默认有这个参数-XX:+UseAdaptiveSizePolicy(默认开启),会导致这个8:1:1比例自动变化,如果不想这个比例有变化可以设置参数-XX:-UseAdaptiveSizePolicy

Minor GC和Full GC 有什么不同呢?

  • Minor GC/Young GC:指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。
  • Major GC/Full GC:一般会回收老年代 ,年轻代,方法区的垃圾,Major GC的速度一般会比Minor GC的慢10倍以上。

大对象直接进入老年代 

  • 大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。
  • JVM参数 -XX:PretenureSizeThreshold 可以设置大对象的大小,如果对象超过设置大小会直接进入老年代,不会进入年轻代,这个参数只在 Serial 和ParNew两个收集器下 有效。
  • 比如设置JVM参数:-XX:PretenureSizeThreshold=1000000 (单位是字节) -XX:+UseSerialGC ,再执行下上面的第一 个程序会发现大对象直接进了老年代 为什么要这样呢? 为了避免为大对象分配内存时的复制操作而降低效率。

长期存活的对象将进入老年代 

  • 既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在 老年代中。
  • 为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。 
  • 如果对象在 Eden 出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为1。
  • 对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁。
  • 当它的年龄增加到一定程度 (默认为15岁,CMS收集器默认6岁,不同的垃圾收集器会略微有点不同),就会被晋升到老年代中。对象晋升到老年代 的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。

对象动态年龄判断

  • 当前放对象的Survivor区域里(其中一块区域,放对象的那块s区),一批对象的总大小大于这块Survivor区域内存大小的50%(-XX:TargetSurvivorRatio可以指定),那么此时大于等于这批对象年龄最大值的对象,就可以直接进入老年代了,
  • 例如Survivor区域里现在有一批对象,年龄1+年龄2+年龄n的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄n(含)以上的对象都放入老年代。这个规则其实是希望那些可能是长期存活的对象,尽早进入老年代。
  • 对象动态年龄判断机制一般是在minor gc之后触发的。

老年代空间分配担保机制

  • 年轻代每次minor gc之前JVM都会计算下老年代剩余可用空间如果这个可用空间小于年轻代里现有的所有对象大小之和(包括垃圾对象)就会看一个“-XX:-HandlePromotionFailure”(jdk1.8默认就设置了)的参数是否设置了
  • 如果有这个参数,就会看看老年代的可用内存大小,是否大于之前每一次minor gc后进入老年代的对象的平均大小。
  • 如果上一步结果是小于或者之前说的参数没有设置,那么就会触发一次Full gc,对老年代和年轻代一起回收一次垃圾,
  • 如果回收完还是没有足够空间存放新的对象就会发生"OOM"
  • 当然,如果minor gc之后剩余存活的需要挪动到老年代的对象大小还是大于老年代可用空间,那么也会触发full gc,fullgc完之后如果还是没有空间放minor gc之后的存活对象,则也会发生“OOM”

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

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

相关文章

好用的便签软件,好用便签排行榜

在生活和工作中&#xff0c;便签软件的使用已经成为我们日常不可或缺的工具。随着技术的发展&#xff0c;便签软件的功能越来越强大&#xff0c;用户也有了更多选择。好用的便签软件有哪些&#xff0c;希望大家能从好用便签排行榜中找到适合自己的工具。 ##1.好用便签 好用便签…

CNC机加工引入复合机器人可以提高生产效率,降低成本

CNC加工企业在过去依赖大量的人工来完成生产线上的各项任务&#xff0c;包括CNC机床的上下料、物料搬运以及部分装配工作。然而&#xff0c;随着产能需求的不断增长和人工成本的持续上升&#xff0c;企业逐渐意识到自动化升级的重要性与迫切性。 面临的挑战与需求&#xff1a; …

Win系统创建虚拟环境利用pyinstaller打包python文件为.exe文件

0. 前提&#xff1a;win系统已经安装Aaconda&#xff0c;检查是否安装成功&#xff0c;命令如下&#xff1a; conda -V输出如下则安装成功&#xff0c;否则需要安装网上教程重新安装一下&#xff08;PS&#xff1a;内存允许的话&#xff0c;建议装固态盘&#xff0c;不然很慢&…

小孩近视用白炽灯好吗?多款热门护眼台灯实测分享

如今对于家长而言&#xff0c;最关心的事情除了孩子的学习成绩以外&#xff0c;最重要的就是孩子的视力健康问题&#xff0c;现在的孩子近视率实在太高了&#xff0c;不少还在小学阶段的学生都开始配戴上了眼镜。所以想要保护孩子的视力健康一盏好的台灯肯定是必不可少的&#…

5G工业网关是什么?

随着科技的飞速发展&#xff0c;5G技术已经逐渐渗透到我们生活的方方面面。而在工业领域&#xff0c;5G工业网关作为连接工业设备与网络的关键组件&#xff0c;正发挥着越来越重要的作用。HiWoo Box其5G工业网关产品以其卓越的性能和稳定性&#xff0c;正助力企业实现数字化转型…

枚举 --java学习笔记

什么是枚举 枚举是一种特殊类 格式&#xff1a; 修饰符 enum 枚举类名{ 名称1&#xff0c;名称2&#xff0c;...&#xff1b; //枚举类的第一行必须罗列的是枚举对象的名字 其他成员... } 枚举类的第一行只能罗列一些名称&#xff0c;这些名称都是常量&#xff0c;…

为什么不用 index 做 key?

“在 Vue 中&#xff0c;我们在使用 v-for 渲染列表的时候&#xff0c;为什么要绑定一个 key&#xff1f;能不能用 index 做 key&#xff1f;” 在聊这个问题之前我们还得需要知道 Vue 是如何操作 DOM 结构的。 虚拟DOM 我们知道&#xff0c;Vue 不可以直接操作 DOM 结构&am…

vscode 使用ssh进行远程开发 (remote-ssh),首次连接及后续使用,详细介绍

在vscode添加remote ssh插件 首次连接 选择左侧栏的扩展&#xff0c;并搜索remote ssh 它大概长这样&#xff0c;点击安装 安装成功后&#xff0c;在左侧栏会出现远程连接的图标&#xff0c;点击后选择ssh旁加号便可以进行连接。 安装成功后vscode左下角会有一个图标 点击图…

LCR 185. 统计结果概率

解题思路&#xff1a; 动态规划 逆向推理会有越界问题&#xff0c; 若希望递推计算 f(2,2)&#xff0c;由于一个骰子的点数和范围为 [1,6] &#xff0c;因此只应求和 f(1,1) &#xff0c;即 f(1,0) , f(1,−1) , ... , f(1,−4) 皆无意义。 故采用正向推理&#xff0c;如下图…

三八妇女节智慧花店/自动售花机远程视频智能监控解决方案

一、项目背景 国家统计局发布的2023年中国经济年报显示&#xff0c;全年社会消费品零售总额471495亿元&#xff0c;比上年增长7.2%。我国无人零售整体发展迅速&#xff0c;2014年市场规模约为17亿元。无人零售自助终端设备市场规模超过500亿元&#xff0c;年均复合增长率超50%。…

C#实现快速排序算法

C#实现快速排序算法 以下是C#中的快速排序算法实现示例&#xff1a; using System;class QuickSort {// 快速排序入口函数public static void Sort(int[] array){QuickSortRecursive(array, 0, array.Length - 1);}// 递归函数实现快速排序private static void QuickSortRecu…

IonIa: High-Performance Replication for Modern Disk-based KV Stores——论文泛读

FAST 2024 Paper 论文阅读笔记整理 问题 键值存储在数据中心应用程序中发挥着核心作用&#xff0c;许多KV存储都是使用写优化索引&#xff08;WOI&#xff09;&#xff08;如LSM[58]&#xff09;构建的&#xff0c;称为WO-KV存储。最近的WO-KV存储针对现代SSD进行了优化&…

python: import用法

目录 1.import1.1从当前文件夹下1.2从python库目录中导入库2.使用1.3 总结1.4 2.定义参考&#xff1a; 1.import 常用 1.1从当前文件夹下 1.2从python库目录中导入库 在控制台通过pip install 库名的命令安装库&#xff0c;库将被安装到python文件夹的库目录下。 2.使用 …

用 ChatGPT 帮自己修英文简历 — 程序员篇

写英文简历一直是许多人的痛处&#xff0c;怎么写得文法正确又吸引人&#xff0c;对于不是英文母语人士的人&#xff0c;是相当困难的。即使网路上有很多教学文&#xff0c;但看完之后还是不知道该怎么描述。导致很多人最后还是去找简历编修。不过现在有了 ChatGPT 这类 AI 工具…

离散数学——(3)联结词及对应的真值指派,最小全功能联结词集,对偶式,范式,范式存在定理,小项

目录 1.联结词及对应的真值指派 2.最小全功能联结词集 3.对偶式 4.范式 1.析取范式 5.范式存在定理 6.小项 1.联结词及对应的真值指派 2.最小全功能联结词集 3.对偶式 4.范式 1.析取范式 5.范式存在定理 6.小项

20个Python函数程序实例

前面介绍的函数太简单了&#xff1a; 以下是 20 个不同的 Python 函数实例 下面深入一点点&#xff1a; 以下是20个稍微深入一点的&#xff0c;使用Python语言定义并调用函数的示例程序&#xff1a; 20个函数实例 简单函数调用 def greet():print("Hello!")greet…

连接kafka报错:java.io.IOException: Can‘t resolve address:

修改电脑host文件:C:\Windows\System32\drivers\etc\hosts 加上一行 192.168.1.XXX MHA_SLAVE2&#xff08;192.168.1.XXX 这个是安装kafka 的服务器地址&#xff0c;MHA_SLAVE2是kafka的容器id&#xff09;

国家妇女节放假是法定的假日

在这个充满活力和希望的春天&#xff0c;我们迎来了一个特殊的节日——国家妇女节。这是一个属于所有女性的节日&#xff0c;是一个庆祝女性成就、关爱女性权益的时刻。在这个特殊的日子里&#xff0c;我们不禁要问&#xff1a;国家妇女节放假是法定假日吗&#xff1f;让我们一…

Vscode连接远程服务器失败解决方案

一、 could not establish connection to “XXX” 尝试使用Remote-SSH插件连接远程的服务器&#xff0c;但是配置显示出错&#xff0c;端口显示试图写入的管道不存在&#xff0c;弹出窗口显示could not establish connection to “XXX” 二、检查Windows的OpenSSH 1.检索是否…

centos设置SSH密钥认证,使用scp命令复制文件

1&#xff09;本地查看是否已经生成SSH密钥&#xff08;id_rsa、id_rsa.pub代表已经有SSH密钥&#xff09;&#xff1a;ls ~/.ssh 2&#xff09;本地生成SSH密钥对&#xff08;我这边3个直接回车&#xff09;&#xff1a;ssh-keygen -t rsa 3&#xff09;将本地公钥(/root/.ssh…