JUC高级八-Java对象内存布局和对象头

news/2024/5/20 7:53:18 标签: java, juc, 对象内存布局, 对象头

JUC高级八-Java对象内存布局对象头

1. 对象的内存布局

在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)实例数据(Instance Data)和对齐填充(Padding)(保证8个字节的倍数) 。

数组对象的对象头比常规对象多一个length,用于记录数组长度

image-20230409093814988

1.1 对象头

1.1.1 对象标记Mark Word

1.1.1.1 32位(看一下即可,不用学了,以64位为准)

image-20230409100947099

1.1.1.2 64位(重要)

image-20230409094132151

image-20230409094748251

image-20230409101153352

  • 默认存储对象的HashCode分代年龄锁标志位等信息。
  • 这些信息都是与对象自身定义无关的数据,所以MarkWord被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据。
  • 它会根据对象的状态复用自己的存储空间,也就是说在运行期间MarkWord里存储的数据会随着锁标志位的变化而变化。
1.1.1.2.1 源码分析

oop.hpp

image-20230409101311307

markOop.hpp

  • hash: 保存对象的哈希码
  • age: 保存对象的分代年龄
    • 从下图age:4可以看出分代年龄用4位表示,那么最大就是二进制1111即十进制15,所以新生代对象晋升为老年代对象需要分代年龄达到15次
  • biased_lock: 偏向锁标识位
  • lock: 锁状态标识位
  • JavaThread* :保存持有偏向锁的线程ID
  • epoch: 保存偏向时间戳

image-20230409101353805

1.1.1.2.2 markword(64位)分布图

对象布局、GC回收和后面的锁升级就是对象标记MarkWord里面标志位的变化

image-20230409101546174

1.1.2 类元信息(又叫类型指针)

image-20230409094415978

对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

对象头多大?

在64位系统中,Mark Word占了8个字节,类型指针占了8个字节,一共是16个字节。

1.2 实例数据

image-20230409095312916

存放类的属性(Field)数据信息,包括父类的属性信息

1.3 对齐填充

虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这部分内存按8字节补充对齐。

Hotspot术语表官网

image-20230409095603588

底层源码理论证明

image-20230409095656594

  • _mark字段是mark word,_metadata是类指针klass pointer,

  • 对象头(object header)即是由这两个字段组成,这些术语可以参考Hotspot术语表,

    image-20230409095905448

2. 聊聊Object obj = new Object()

2.1 JOL工具–分析对象在JVM的大小和分布

JOL官网

pom依赖

<!--
官网:http://openjdk.java.net/projects/code-tools/jol/
定位:分析对象在JVM的大小和分布
-->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

2.1.1 VM的细节详细情况示例

java">package site.zhourui.juc.objectHead;

import org.openjdk.jol.vm.VM;

public class JOLDemo {
    public static void main(String[] args) {
        //VM的细节详细情况
        System.out.println(VM.current().details());
        //对象对齐:所有的对象分配的字节都是8的整数倍。
        System.out.println(VM.current().objectAlignment());
    }
}

执行结果:

打印出VM的细节详细情况及对象对齐

image-20230409102937560

2.1.2 查看Object内存布局示例

java">package site.zhourui.juc.objectHead;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

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

执行结果

之前说类型指针是8个字节现在只有4个字节?后面解释

image-20230409103905855

2.1.3 只有对象头没有其他任何示例数据的对象内存布局

java">package site.zhourui.juc.objectHead;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

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

class Customer{//只有一个对象头的实例对象,16字节(忽路压缩指针的影响)+4字节+1字=-21字节----》对其填充,24字节
}

执行结果:

我们发现与new一个Object的对象内存布局一样的

image-20230409104253506

2.1.4 有实例数据对象内存布局

java">package site.zhourui.juc.objectHead;

import org.openjdk.jol.info.ClassLayout;
import org.openjdk.jol.vm.VM;

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

class Customer{//只有一个对象头的实例对象,16字节(忽路压缩指针的影响)+4字节+1字=-21字节----》对其填充,24字节
    int id;
    boolean flag;
}

image-20230409104640034

2.1.5 GC年龄采用4位bit存储,最大为15,例如MaxTenuringThreshold参数默认值就是15

设置虚拟机分代年龄参数为16-XX:MaxTenuringThreshold=16

image-20230409105113817

执行结果:

说虚拟机分代年龄只能是0到15

image-20230409105131156

2.1.6 尾巴参数之压缩指针相关说明

2.1.6.1 查看jvm启动默认参数

-XX:+PrintCommandLineFlags -version

执行结果:

发现jvm启动的时候是默认帮我们开启了压缩指针UseCompressedClassPointers

就会导致我们的类型指针本来是8字节被压缩为4个字节

image-20230409105522364

2.1.6.2 关闭压缩指针再次查看对象内存布局

-XX:-UseCompressedClassPointers

执行结果:

发现没有对齐填充了,我们的类型指针是8字节

image-20230409110004849


http://www.niftyadmin.cn/n/212811.html

相关文章

C++ 图系列之基于有向无环图的拓扑排序算法

1. 前言 有向无环图&#xff0c;字面而言&#xff0c;指图中不存在环(回路)&#xff0c;意味着从任一顶点出发都不可能回到顶点本身。有向无环图也称为 DAG&#xff08;Directed Acycline Graph&#xff09;。 有向无环图可用来描述顶点之间的依赖关系&#xff0c;依赖这个概…

【ROS】基于WIFI网络实现图像消息跨机实时传输

【开发背景】 研究机器人目标检测算法的时候&#xff0c;常常需要把推理图像实时展示出来&#xff0c;以供观摩。而ROS1提供的跨机通信方法&#xff0c;要么是配置单Master&#xff0c;要么是配置多Master&#xff1b;一方面配置麻烦&#xff0c;另一方面传输效率低下&#xf…

Math类,Array类

Math的方法大都是静态的可以直接引用 package com.jshedu.Math_;/*** author jia* version 1.0*/ public class MathMethod {public static void main(String[] args) {//看看Math常用的方法(静态方法)//1.abs 绝对值int abs Math.abs(-9);System.out.println(abs);//9//2.pow…

手写vuex4源码(六)命名空间实现

一、命名空间使用 在子模块对象中添加 namespaced&#xff1a;true&#xff0c;为模块开启命名空间功能&#xff1b; 开启命名空间功能&#xff0c;相当于为每个模块添加独立的作用域&#xff0c;实现模块间状态和事件的隔离&#xff1b; 二、命名空间实现逻辑 在模块注册阶…

EMC-MLCC电容反谐振点引起的RE辐射超标

MLCC电容反谐振点引起的RE辐射超标 对待RE辐射问题&#xff0c;可以按照干扰源&#xff0c;干扰路径&#xff0c;被干扰源&#xff0c;入手较多的是干扰源和干扰路径&#xff0c; 解决干扰源可以从展频&#xff0c;调频&#xff0c;屏蔽干扰源&#xff0c;增加RC snabber吸收…

地理信息系统(ArcGIS)在水文水资源、水环境中的实践技术应用及案例分析

目录 专题一 ArcGIS&#xff1a;数据管理 专题二 ArcGIS&#xff1a;数据转换 专题三 ArcGIS&#xff1a;地图制作 专题四 水文水环境数据编辑与管理 专题五 水文水环境数据处理与分析 专题六 ArcGIS水文分析及流域特征提取 专题七 湖泊水库水环境监测及评价 专题八 河…

【ROS2指南-19】使用Launch启动/监控多个节点

ROS 2 启动系统 ROS 2 中的启动系统负责帮助用户描述他们系统的配置&#xff0c;然后按照描述执行。系统的配置包括要运行的程序、运行它们的位置、传递给它们的参数以及 ROS 特定约定&#xff0c;这些约定通过为它们提供不同的配置&#xff0c;使得在整个系统中重用组件变得容…

校园一键报警柱的作用

校园一键报警柱是一种用于校园安全的紧急报警系统&#xff0c;可以随时随地向校园安全管理部门发送紧急警报。这种系统通常采用带有紧急按钮的电缆或无线警报装置&#xff0c;使学生、教师和工作人员可以在出现紧急情况时轻松报告安全问题&#xff0c;迅速地通知校园安全人员&a…