Java对象内存布局和对象头

简介: Java对象内存布局和对象头
Object obj = new Object();  //new 一个对象,占内存多少? 没有实例数据的话,就是16个字节


1、对象的内存布局


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

1673417457180.jpg

2、对象在堆内存中的存储布局

1673417470151.jpg

Mark Word:对象标记

Class Pointer:类元信息(又叫类型指针)


对象内部结构分为:对象头、实例数据、对齐填充(保证8个字节的倍数,8、16、24。。。)。

对象头分为对象标记(markOop)和类元信息(klassOop),类元信息存储的是指向该对象类元数据(klass)的首地址。


1、对象头


1、对象标记Mark Word

1673417500752.jpg

1673417511767.jpg

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

1673417519503.jpg

对象标记(Mark Word)默认存储对象的HashCode、分代年龄和锁标志位等信息。

这些信息都是与对象自身定义无关的数据,所以MarkWord被设计成一个非固定的数据结构以便在极小的空间内存存储尽量多的数据。

它会根据对象的状态复用自己的存储空间,也就是说在运行期间MarkWord里存储的数据会随着锁标志位的变化而变化。


2、类元信息(又叫类型指针)


1673417540723.jpg

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


3、对象头多大


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


2、实例数据


存放类的属性(Field)数据信息,包括父类的属性信息(类属性),如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐


3、实例填充


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


http://openjdk.java.net/groups/hotspot/docs/HotSpotGlossary.html


http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/89fb452b3688/src/share/vm/oops/oop.hpp

1673417578027.jpg

_mark字段是mark word,_metadata是类指针klass pointer, 对象头(object header)即是由这两个字段组成,这些术语可以参考Hotspot术语表,


每个对象都有class pointer(类型指针)和 header word(对象标记)


4、Mark Word

1673417595907.jpg


1、oop.hpp

1673417607983.jpg

2、markOop.hpp


hash: 保存对象的哈希码
age: 保存对象的分代年龄
biased_lock: 偏向锁标识位
lock: 锁状态标识位
JavaThread* :保存持有偏向锁的线程ID
epoch: 保存偏向时间戳

1673417625355.jpg

markword(64位)分布图,对象布局、GC回收和后面的锁升级就是对象标记MarkWord里面标志位的变化

1673417633657.jpg

5、Object obj = new Object()解析


1、JOL证明


JOL

<!--
定位:分析对象在JVM的大小和分布
-->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>
public class MyObject
{
    public static void main(String[] args){
        //VM的细节详细情况
        System.out.println(VM.current().details());
        //所有的对象分配的字节都是8的整数倍。
        System.out.println(VM.current().objectAlignment());
    }
}

1673417676014.jpg

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

1673417694177.jpg

OFFSET 偏移量,也就是到这个字段位置所占用的byte数
SIZE 后面类型的字节大小
TYPE 是Class中定义的类型
DESCRIPTION DESCRIPTION是类型的描述
VALUE VALUE是TYPE在内存中的值


2、换成其他对象

1673417745283.jpg


3、对象分代年龄


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


添加运行参数:-XX:MaxTenuringThreshold=16

1673417756710.jpg

4、默认开启压缩说明


运行参数:把启动配置参数打印出来

java -XX:+PrintCommandLineFlags -version


1673417763967.jpg

说明运行默认开启压缩类型指针


手动关闭压缩再看看


+就是开始,-就是关闭

-XX:-UseCompressedClassPointers

1673417781223.jpg

手动配置,关闭压缩指针,就没有了对齐填充,直接到 8 + 8 = 16字节

相关文章
|
12天前
|
缓存 easyexcel Java
Java EasyExcel 导出报内存溢出如何解决
大家好,我是V哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。以下是V哥整理的解决该问题的一些常见方法,包括分批写入、设置合适的JVM内存、减少数据对象的复杂性、关闭自动列宽设置、使用Stream导出以及选择合适的数据导出工具。此外,还介绍了使用Apache POI的SXSSFWorkbook实现百万级别数据量的导出案例,帮助大家更好地应对大数据导出的挑战。欢迎一起讨论!
106 1
|
5天前
|
安全 Java 编译器
Java对象一定分配在堆上吗?
本文探讨了Java对象的内存分配问题,重点介绍了JVM的逃逸分析技术及其优化策略。逃逸分析能判断对象是否会在作用域外被访问,从而决定对象是否需要分配到堆上。文章详细讲解了栈上分配、标量替换和同步消除三种优化策略,并通过示例代码说明了这些技术的应用场景。
Java对象一定分配在堆上吗?
|
9天前
|
Java API
Java 对象释放与 finalize 方法
关于 Java 对象释放的疑惑解答,以及 finalize 方法的相关知识。
33 17
|
1天前
|
存储 Java 编译器
Java内存模型(JMM)深度解析####
本文深入探讨了Java内存模型(JMM)的工作原理,旨在帮助开发者理解多线程环境下并发编程的挑战与解决方案。通过剖析JVM如何管理线程间的数据可见性、原子性和有序性问题,本文将揭示synchronized关键字背后的机制,并介绍volatile关键字和final关键字在保证变量同步与不可变性方面的作用。同时,文章还将讨论现代Java并发工具类如java.util.concurrent包中的核心组件,以及它们如何简化高效并发程序的设计。无论你是初学者还是有经验的开发者,本文都将为你提供宝贵的见解,助你在Java并发编程领域更进一步。 ####
|
1天前
|
存储 安全 Java
什么是 Java 的内存模型?
Java内存模型(Java Memory Model, JMM)是Java虚拟机(JVM)规范的一部分,它定义了一套规则,用于指导Java程序中变量的访问和内存交互方式。
8 1
|
8天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
7天前
|
存储 运维 Java
💻Java零基础:深入了解Java内存机制
【10月更文挑战第18天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
21 1
|
10天前
|
存储 算法 Java
Java虚拟机(JVM)的内存管理与性能优化
本文深入探讨了Java虚拟机(JVM)的内存管理机制,包括堆、栈、方法区等关键区域的功能与作用。通过分析垃圾回收算法和调优策略,旨在帮助开发者理解如何有效提升Java应用的性能。文章采用通俗易懂的语言,结合具体实例,使读者能够轻松掌握复杂的内存管理概念,并应用于实际开发中。
|
17天前
|
存储 Java 数据管理
Java零基础-Java对象详解
【10月更文挑战第7天】Java零基础教学篇,手把手实践教学!
23 6
|
17天前
|
存储 监控 算法
Java中的内存管理与垃圾回收机制解析
本文深入探讨了Java编程语言中的内存管理方式,特别是垃圾回收机制。我们将了解Java的自动内存管理是如何工作的,它如何帮助开发者避免常见的内存泄漏问题。通过分析不同垃圾回收算法(如标记-清除、复制和标记-整理)以及JVM如何选择合适的垃圾回收策略,本文旨在帮助Java开发者更好地理解和优化应用程序的性能。