首页 > 其他分享 >JVM虚拟机系统性学习-对象的创建流程及对象的访问定位

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位

时间:2023-12-17 13:32:09浏览次数:37  
标签:存储 Eden Survivor 对象 虚拟机 8B JVM 年代

对象的创建流程与内存分配

对象创建流程如下:

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_垃圾回收


Java 中新创建的对象如何分配空间呢?

  1. new 的对象先放 Eden 区(如果是大对象,直接放入老年代)
  2. 当 Eden 区满了之后,程序还需要创建对象,则垃圾回收器会对 Eden 区进行垃圾回收
  3. 在垃圾回收的时候,会将 Eden 区的幸存对象转移到 Survivor From 区
  4. 如果再次触发垃圾回收,此时将 Eden 区的幸存对象转移到 Survivor To 区中,并且将 Survivor From 区中的幸存对象也转移到 Survivor To 区
  5. 如果再次出发垃圾回收,此时将 Eden 区和 Survivor To 区中的幸存对象转移到 Survivor From 区中
  6. 当对象的生存年龄达到 15 时,会被放入老年代

在幸存对象每次转移的时候,对会将对象的生存年龄 + 1,达到 15 时会放入老年代中


Java 对象只会分配在堆中吗?

不是的,如果经过 逃逸分析 后发现,一个对象并没有逃逸出方法的话,就可能被优化为在栈上分配,这是常见的堆外存储技术。

逃逸分析就是分析对象动态作用域:

  • 对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸
  • 对象在方法中被定义后,对象被外部方法所引用,则认为发生逃逸
在 HashMap 中就将变量声明在方法中,可以将变量存储在栈中,提升速度

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_垃圾回收_02


什么情况下,对象会直接进入老年代?

  • 对象存储年龄默认超过 15 次(-XX:MaxTenuringThreshold)
  • 动态年龄判断:Minor GC 之后,发现 Survivor 区中一批对象的总大小大于这块 Survivor 区的 50%,那么会将此时大于这批对象年龄最大值的所有对象放入老年代,如:一批对象年龄分别为3,4,5,这批对象的总和大于 Survivor 区的 50%,那么会将年龄大于 5 的对象放入老年代
  • 大对象直接进入老年代:前提是 Serial 和 ParNew 收集器
  • MinorGC 后,存活对象太多无法放入 Survivor


空间担保机制: 空间担保是在 老年代 中进行空间分配担保

空间担保指的是在 MinorGC 前,会判断老年代可用内存是否大于新生代全部对象大小,如果大于,则此次 Minor GC 是安全的

如果小于,则会检查老年代最大连续可用空间是否大于 历次晋升到老年代对象的平均大小,如果大于,则尝试 Minor GC;如果小于,则进行 Full GC


老年代的空间担保如下图:

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_老年代_03


对象内存布局

对象存储在堆内存中主要分为三块区域:

  1. 对象头(Header):Java 对象头占 8B,如果是数组则占 12 B,因为数组还需要 4B 存储数组大小,对象头又分为:
  • 标记字段 MarkWord
  • 存储对象自身运行时的数据,synchronized 实现的轻量级锁和偏向锁就在这里设置
  • 默认存储:对象 HashCode、GC 分代年龄、锁状态等等
  • 类型指针 KlassPoint
  • KlassPoint 是对象指向它的类元数据的指针,来确定这个对象是哪个类的实例对象
  • 开启指针压缩后存储空间为 4B,不开为 8B
  • 数组长度:如果对象是数组,则记录,占 4B
  • 对其填充:保证数组的大小永远是 8B 的整数倍
  1. 示例数据(Instance Data):生成对象时,对象的非静态成员变量也会在堆内存中存储
  2. 对齐填充(Padding):JVM 内对象都采用 8B 对齐,不够 8B 的会自动补齐

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_数组_04


对象头的信息并非是固定的,根据对象状态的不同,对象头存储的信息也是不同的,在 JDK1.8 中如下图:

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_老年代_05


打印对象的内存布局信息:

引入依赖:

<dependency>
  <groupId>org.openjdk.jol</groupId>
  <artifactId>jol-core</artifactId>
  <version>0.9</version>
</dependency>

代码:

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    }
}


控制台打印如下,对象头占 12B(MarkWord 8B + KlassPoint 4B),有 4B 的对齐填充,实例数据 0B,因此整个对象大小为 16B

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_垃圾回收_06


对象的访问定位

有两种方式:

  • 通过句柄访问:稳定,对象被移动只需要修改句柄中的地址
  • 通过直接指针访问:访问速度快,节省了一次指针定位的开销

句柄访问如下图:

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_数组_07


直接指针访问如下图:

JVM虚拟机系统性学习-对象的创建流程及对象的访问定位_垃圾回收_08


标签:存储,Eden,Survivor,对象,虚拟机,8B,JVM,年代
From: https://blog.51cto.com/u_16186397/8861409

相关文章

  • JVM虚拟机系统性学习-对象的创建流程及对象的访问定位
    欢迎关注公众号:【11来了】可以查看深入理解Redis系列完整文章!作者为在读研究生,目前研二,计划在公众号记录学习常用中间件笔记,以及明年更新面试经历!对象的创建流程与内存分配对象创建流程如下:Java中新创建的对象如何分配空间呢?new的对象先放Eden区(如果是大对象,直接放入老年代)当......
  • VMware workstation中安装的centos虚拟机ip自动获取可以上网,设置静态ip不能上网问题解
    一、需求   linux中我们会设置hosts文件,这会涉及ip和域名的设置,但是如果虚拟机自动获取ip地址的话,这就意味着之前设置的hosts文件需要重新修改,所以我们需要设置虚拟机为静态ip地址。二、故障现象   我linux虚拟机最开始是自动获取的ip地址,用的nat模式,是可以上网的,......
  • 面向对象
    前言:面向对象(oop)是一种编程方法,编程思想,适用于中大型项目;面向过程也是一种编程思想,适用于小型项目。面向过程和面向对象都可以实现某个编程目的,面向过程考虑的是实现的细节;面向对象考虑的是结果(谁能做这件事)。 面向对象类class:是对具有相同特征或者行为的事物的统......
  • JVM虚拟机系统性学习-运行时数据区(方法区、程序计数器、直接内存)
    方法区方法区本质上是Java编译后代码的存储区域,存储了每一个类的结构信息,如:运行时常量池、成员变量、方法、构造方法和普通方法的字节码指令等内容方法区主要存储的数据如下:Class类型信息,如该Class为class类、接口、枚举、注解,类的修饰符等等信息方法信息(方法名称、方法返回......
  • Python学习之十六_virsh批量获取虚拟机IP地址的方法
    Python学习之十六_virsh批量获取虚拟机IP地址的方法Linux命令说明forjin\$(foriin`virshlist|grep-vId|greprunning|awk'{print$2}'`;\dovirshdumpxml$i|grep"macaddress"|awk-F\''{print$2}'&&e......
  • 前端JavaScript中,对obj对象进行劫持的方式主要有以下几种:
    前端JavaScript中,对obj对象进行劫持的方式主要有以下几种:原型劫持:通过改变对象的原型(prototype)来实现劫持。当一个对象被创建时,它的原型会被存储起来,以便在需要时进行查找。通过将一个对象的原型改为另一个对象或null,可以控制该对象的属性和方法。属性访问劫持:通过在属性访问时......
  • JVM虚拟机系统性学习-运行时数据区(虚拟机栈、本地方法栈)
    虚拟机栈虚拟机栈为每个线程所私有的,如下图:栈帧是什么?栈帧存储了方法的局部变量表、操作数栈、动态链接和方法返回地址等信息栈内存为线程私有的空间,每个方法在执行时都会创建一个栈帧,执行该方法时,就会将该方法所对应的栈帧入栈局部变量表:用于存储方法参数和定义在方法体内部的局部......
  • python高级之函数对象与闭包函数
    函数对象和闭包函数函数对象1,什么是函数对象?函数对象简单理解就是将函数当变量来使用。如下图所示:定义一个函数可以简单的理解为:func=函数体内存地址函数名+()–>调用函数函数名-->函数对象,函数名不加括号此时的函数名就是函数对象函数用于赋值将函数赋值给某个变......
  • openGauss学习笔记-160 openGauss 数据库运维-备份与恢复-导出数据-使用gs_dump和gs_d
    openGauss学习笔记-160openGauss数据库运维-备份与恢复-导出数据-使用gs_dump和gs_dumpall命令导出数据-导出所有数据库-导出全局对象160.1导出全局对象openGauss支持使用gs_dumpall工具导出所有数据库公共的全局对象,包含数据库用户和组、表空间及属性(例如:适用于数据库整体的......
  • 秦疆的Java课程笔记:72 面向对象 instanceof和类型转换
    instanceof关键字,用于判断左边的实例对象是否是右边的类的实例。先创建4个类,父类Person,其子类Student和Teacher,测试类Application。在Application中测试instanceof语句://父类publicclassPerson{}//子类publicclassTeacherextendsPerson{}//子类publicclassStud......