JVM - 剖析Java对象头Object Header之对象大小
文章目录
- Pre
- 总览
- 对象头剖析
- 查看对象内存的占用情况
- 对象头C++源码 注释
Pre
JVM - 写了这么多年代码,你知不道new对象背后的逻辑? 中大体介绍了Java中 new 对象背后的主要流程,其中对象头的部分,我们仅仅是点到为止,这里我们深入剖一下Object Header的奥秘 。
总览
初始化默认值以后,JVM要对对象进行必要的设置,例如这个对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等信息。这些信息存放在对象的对象头Object Header之中。 这部分数据的长度在32位和64位的虚拟机中分别为32个和64个bits,官方称它为“Mark Word”。
在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header)、 实例数据(Instance Data)和和对齐填充(Padding) 。
HotSpot虚拟机的对象头包括两部分信息
- 第一部分用于存储对象自身的运行时数据, 如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时 间戳等。
我们以32位操作系统的组成来看一下,下面这个图也是从网上找的,感觉很清晰
- 对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。
如下红色框框中的示意图
对象头剖析
查看对象内存的占用情况
推荐openjdk的jol工具, 可以查看对象内存的占用情况。
添加依赖
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.10</version
</dependency>
示例
import org.openjdk.jol.info.ClassLayout;/*** @author 小工匠* @version v1.0* @create 2020-06-25 16:21* @motto show me the code ,change the word* @blog https://artisan.blog.csdn.net/* @description**/public class ObjectHeaderTest {public static void main(String[] args) {ClassLayout layout = ClassLayout.parseInstance(new Object());System.out.println(layout.toPrintable());System.out.println();ClassLayout layout1 = ClassLayout.parseInstance(new int[]{});System.out.println(layout1.toPrintable());System.out.println();ClassLayout layout2 = ClassLayout.parseInstance(new ArtisanTest());System.out.println(layout2.toPrintable());}// -XX:+UseCompressedOops 默认开启的压缩所有指针// -XX:+UseCompressedClassPointers 默认开启的压缩对象头里的类型指针Klass Pointer// Oops : Ordinary Object Pointerspublic static class ArtisanTest {//8B mark word//4B Klass Pointer 如果关闭压缩-XX:-UseCompressedClassPointers或-XX:-UseCompressedOops,则占用8Bint id; //4BString name; //4B 如果关闭压缩-XX:-UseCompressedOops,则占用8Bbyte b; //1BObject o; //4B 如果关闭压缩-XX:-UseCompressedOops,则占用8B}
}
【输出结果 】
java.lang.Object object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)12 4 (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total[I object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 01 00 00 00 (00000001 00000000 00000000 00000000) (1)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 6d 01 00 f8 (01101101 00000001 00000000 11111000) (-134217363)12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)16 0 int [I.<elements> N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes totalcom.gof.test.ObjectHeaderTest$ArtisanTest object internals:OFFSET SIZE TYPE DESCRIPTION VALUE0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)8 4 (object header) 63 cc 00 f8 (01100011 11001100 00000000 11111000) (-134165405)12 4 int ArtisanTest.id 016 1 byte ArtisanTest.b 017 3 (alignment/padding gap) 20 4 java.lang.String ArtisanTest.name null24 4 java.lang.Object ArtisanTest.o null28 4 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 3 bytes internal + 4 bytes external = 7 bytes totalProcess finished with exit code 0
【结果说明】
3中类型 : new Object() | new int[]{}数组 | new ArtisanTest()
我这个电脑是64位的操作系统,所以 mark word 占 8个字节。JDK8 klass point 默认开启了指针压缩,所以是4个字节 , 不足8的倍数的,使用padding对齐填充,其目的是为了计算机高效寻址。
最后一个,对于包含多个变量的对象的对象头
对象头C++源码 注释
Bit‐format of an object header (most significant first, big endian layout below):
//
// 32 bits:
// ‐‐‐‐‐‐‐‐
// hash:25 ‐‐‐‐‐‐‐‐‐‐‐‐>| age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:23 epoch:2 age:4 biased_lock:1 lock:2 (biased object)
// size:32 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (CMS free block)
// PromotedObject*:29 ‐‐‐‐‐‐‐‐‐‐>| promo_bits:3 ‐‐‐‐‐>| (CMS promoted object)
//
// 64 bits:
// ‐‐‐‐‐‐‐‐
// unused:25 hash:31 ‐‐>| unused:1 age:4 biased_lock:1 lock:2 (normal object)
// JavaThread*:54 epoch:2 unused:1 age:4 biased_lock:1 lock:2 (biased object)
// PromotedObject*:61 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| promo_bits:3 ‐‐‐‐‐>| (CMS promoted object)
// size:64 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (CMS free block)
//
// unused:25 hash:31 ‐‐>| cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && normal object)
// JavaThread*:54 epoch:2 cms_free:1 age:4 biased_lock:1 lock:2 (COOPs && biased object)
// narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ‐‐‐‐‐>| (COOPs && CMS promoted object)
// unused:21 size:35 ‐‐>| cms_free:1 unused:7 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐>| (COOPs && CMS free block)
JVM - 剖析Java对象头Object Header之对象大小相关推荐
- JVM - 剖析Java对象头Object Header之指针压缩
文章目录 Pre 指针压缩 论证压缩效果 UseCompressedOops & UseCompressedClassPointers [指针压缩]开启 VS 关闭 指针压缩的目的 为什么堆内 ...
- java的头怎么写_JAVA对象布局之对象头(Object Header)
由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 .在学习并发编程知识synchronized时,我们总是难以理解其实 ...
- JAVA对象布局之对象头(Object Header)
由于Java面向对象的思想,在JVM中需要大量存储对象,存储时为了实现一些额外的功能,需要在对象中添加一些标记字段用于增强对象功能 .在学习并发编程知识synchronized时,我们总是难以理解其实 ...
- 什么是一等对象 first-class object(第一类对象)?
什么是一等对象 first-class object(第一类对象)? 文章目录 什么是一等对象 first-class object(第一类对象)? 0. 参考资料 1. 定义 0. 参考资料 htt ...
- java线程堆栈_深入JVM剖析Java的线程堆栈
在这篇文章里我将教会你如何分析JVM的线程堆栈以及如何从堆栈信息中找出问题的根因.在我看来线程堆栈分析技术是Java EE产品支持工程师所必须掌握的一门技术.在线程堆栈中存储的信息,通常远超出你的想象 ...
- 【Java】Java 对象头 真的是 32位 吗?
1.概述 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域: 对象头(Header) 实例数据(Instance Data) 对齐填充(Padding). 是真的吗?假的! 假的!!! ...
- 64位JVM的Java对象头详解
关注"Java艺术"一起来充电吧! 我们编写一个Java类,编译后会生成.class文件,当类加载器将class文件加载到jvm时,会生成一个Klass类型的对象(c++),称为类 ...
- java对象头_浅谈java对象结构 对象头 Markword
概述 对象实例由对象头.实例数据组成,其中对象头包括markword和类型指针,如果是数组,还包括数组长度; | 类型 | 32位JVM | 64位JVM| | ------ ---- | ----- ...
- 深入理解JVM(1)——Java内存区域与Java对象
最近放暑假在家,没有实验室的工作要做,正好趁这个时间恶补了之前一知半解的JVM知识,使用的主要学习资料是周志明大大的<深入理解Java虚拟机--JVM高级特性与最佳实践>,我仔细拜读了两遍 ...
最新文章
- PPP协议的CHAP验证
- RxJs SwitchMapTo 操作符之移花接木
- 实现tree系统命令
- 160 - 5 ajj.2
- 第四十期:2019年度十大Web开发趋势
- python集群到hadoop_如何使用Hadoop流在本地Hadoop集群中运行MRJob?
- composer中文阿里云镜像地址
- 会动的图解 | 既然IP层会分片,为什么TCP层也还要分段?
- 【译】Tim Rose 的kibana插件教程-自定义App插件
- string中内容的访问
- VB 按指定编码格式写入文本文件
- Spark中 RDD之coalesce与repartition区别
- MySQL主从复制 + Mycat实现读写分离
- java uml Rose_Rational Rose与UML教程
- 050、动手实验:使用 jstat 摸清线上系统的JVM运行状况
- 谈谈web打印快递单及经验
- excel表格打印每页都有表头_Excel打印时如何实现每一页纸上都有表头?
- springboot学习(六十七) springboot项目通过gradle-docker-plugin插件构建为doker镜像并推送至镜像私服
- oracle脏读查询,没有进行commit操作的数据是否能被查询到,关于oracle的脏读和隔离级别...
- EP Henry推出世界首批用二氧化碳固化的Solidia Concrete制造的预制产品
热门文章
- mysql 5.6 双向互备_mysql双主互备
- OpenCV-Python Feature2D 特征点检测 (SIFT,SURF)
- python 、example
- 如何将html表单转换成url,JS表单传值和URL编码转换
- centos7 mysql读写监控_Centos7 Zabbix监控mysql
- 论文笔记:Integrating Classification and Association Rule Mining (即,CBA算法介绍)
- matlab画一个局部放大的图中图
- 深度2万字好文:图像处理-基于 PyTorch 的 YOLO v5 表情识别(附源代码)
- Python简明教程
- 新浪微博API OAuth 2 Python客户端