IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JVM-03.对象创建与内存分配 -> 正文阅读

[Java知识库]JVM-03.对象创建与内存分配

1.对象创建的流程

类加载检查
类是否已加载?
加载类
分配内存
初始化
设置对象头
执行<init>方法

1.类加载检查
???????当JVM执行一条new指令时,最开始会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、验证、解析、初始化。如果没有,执行响应的类加载过程。
???????new指令对应到语言层面上讲是,new关键词、对象克隆、对象序列化等。

2.内存分配
???????类加载完成后,JVM会对新的对象分配内存空间。对象所需的内存大小在类加载完成后就已经可以完全确定。
???????分配方式有 两种:“指针碰撞”“空闲列表” ,选择哪种分配方式由 Java 堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

  • 指针碰撞:
    ??????? 如标记整理法和复制算法,JVM内存的没有内存碎片,用过的内存和没用的内存完美区分,中间有一个指针作为分界点,那么再分配内存的时候只需要将指针挪动与对象大小相等的距离。

  • 空闲列表:
    ??????? 如垃圾回收的标记清除法清理后的内存区域,JVM中有内存碎片,无法使用简单的指针碰撞进行内存 的划分。索引在JVM内部就维护这一关列表,记录这哪一块的内存是可用的。在分配内存时,从中找到足够的的一片分配给该对象,最后更新记录的表。

  • 并发问题
    ??????? 当同时有多个对象创建是难免会出现并发问题,为了解决此问题,JVM也提供了相应的解决方式。
    ??????? CAS(Compare And Swap)
    ??????? JVM结合CAS和volatile可以实现无锁并发来保证更新操作的原子性,CAS详解见链接: JVM内存模型.
    ??????? 本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)
    ??????? 把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块内存。
    ??????? 通过-XX:+/-UseTLAB参数来控制虚拟机是否使用TLAB(默认开启),-XX:TLABSize 指定缓冲区大小。
    3.初始化
    ??????? 内存分配完成后,虚拟机需要将分配到的内存空间(除对象头外)都初始化为零值(如:String a = 1;赋零值 null),若使用TLAB,这一过程也可以提前至TLAB分配时进行。该操作保证了对象的实例字段在Java代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
    4.设置对象头
    ??????? 初始化零值之后,虚拟机要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头Object Header之中。 在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data) 和对齐填充(Padding)。HotSpot虚拟机的对象头包括两部分信息,第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
    在这里插入图片描述

什么是java对象的指针压缩?
??????? 1.JDK1.6 开始,在64bit操作系统中,JVM支持指针压缩。
??????? 2.启用指针压缩:-XX:+UseCompressedOops(默认开启),禁止指针压缩:-XX:-UseCompressedOop (use compressed-- ordinary object pointer 使用压缩对象指针)。
为什么要进行指针压缩?
??????? 1.在64位平台的HotSpot中使用32位指针,内存使用会多出1.5倍左右,使用较大指针在主内存和缓存之间移动数据, 占用较大带宽,同时GC也会承受较大压力。
??????? 2.减少64位平台下内存的消耗。
??????? 3.在jvm中,32位地址最大支持4G内存(2^32bit),可以通过对对象指针的压缩编码、解码方式进行优化,使得jvm 只用32位地址就可以支持更大的内存配置(小于等于32G)。
??????? 4.堆内存小于4G时,不需要启用指针压缩,jvm会直接去除高32位地址,即使用低虚拟地址空间。
??????? 5.堆内存大于32G时,压缩指针会失效,会强制使用64位(即8字节)来对java对象寻址,故堆内存不要大于32G为好。

5.执行init方法
???????赋属性值(非零值)及执行构造方法。

2.对象的内存分配

在这里插入图片描述

对象内存分配流程图

对象在栈上的分配 :
??????? JVM内存分配对象内存都是在堆中进行分配的,但是对象较多时,会给GC带来较大的压力,直接影响程序的性能。因此出现了栈上分配,当JVM通过逃逸分析判断该对象是否会被外部引用,如果不会且栈上的空间足够,就会将该对象占用的内存在栈上分配。这样该对象的内存就随着栈帧出栈而销毁,从而减少GC压力。链接: 逃逸分析.

??????? JVM通过逃逸分析参数(-XX:+DoEscapeAnalysis)来优化对象内存分配位置(JDK7后默认开启),使其通过标量替换优先分配在栈上。

标量替换: 通过逃逸分析确定该对象不会被外部访问,并且对象可以被进一步分解时,JVM不会创建该对象,而是将该对象成员变量分解若干个被这个方法使用的成员变量所代替,这些代替的成员变量在栈帧或寄存器上分配空间,这样就不会因为没有一大块连续空间导致对象内存不够分配。
开启标量替换参数(-XX:+EliminateAllocations),JDK7之后默认开启,关闭逃逸分析此参数失效。

标量与聚合量: 标量是不可被进一步分解的量,JAVA的基本数据类型就是标量(如:int,double等基本数据类型以及reference类型等)。 聚合量是可以被进一步分解的量。JAVA中一些对象就是可以被进一步分解的聚合量。

对象在新生代的分配 :
??????? 绝大多数情况下,对象分配在Eden区。当Eden区空间不足时,触发Minor GC,剩余存活的对象复制到survivor区,下一次Eden区满后,又会再次触发Minor GC,将eden区和survivor区垃圾对象回收,并将剩余的存活对象移动到另一块存活的survivor区。

注意: 当Eden区空间不足且survivor不足以容纳新生代的对象时会提前移到老年代中去。

??????? 新生代对象大多存活时间很短,JVM默认eden:from:to区8:1:1,如果不开启参数-XX:-UseAdaptiveSizePolicy关闭自适应这个比例会动态变化。设置时eden区尽量的大,survivor区够用即可。

大对象的分配 :
??????? 大对象ParNew、SerialGC垃圾回收器有效。参数设置为-XX:PretenureSizeThreshold=1024(字节) -XX:+UseSerialGC,其他垃圾收集器不支持,如G1有自己的定义大对象定义,直接挪动到老年代能减少垃圾回收
逃逸分析后栈存储对象相对来说较少

长期存活的对象将进入老年代 :
??????? 虚拟机给每个对象设置了一个对象年龄(Age)计数器。 如果对象在 Eden出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为1。对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁,当它的年龄增加到一定程度 (默认为15岁,CMS收集器默认6岁,不同的垃圾收集器会略微有点不同),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。

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

老年代空间分配担保机制 :

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-26 11:56:40  更:2021-07-26 11:57:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/26 1:09:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码