java对象头信息

java对象头信息做 java 开发几年了 但一直不知道如下问题 1 一个 java 对象到底占用了多少内存空间 应该如何计算 2 为什么在 jdk1 6 后 synchronized 关键字性能有所提高 为什么会提高 并且很多文章中都说 synchronized 锁有偏向锁 轻量锁 重量锁等状态 3 java 对象是在那里设置了指针指向对应的方法区中的元数据的 4 在 jvm 垃圾回收时被标记为可回收但还未执行回

做java开发几年了,但一直不知道如下问题:

1. 一个java对象到底占用了多少内存空间,应该如何计算?

2. 为什么在jdk1.6后,synchronized关键字性能有所提高,为什么会提高?并且很多文章中都说synchronized锁有偏向锁、轻量锁、重量锁等状态?

3. java对象是在那里设置了指针指向对应的方法区中的元数据的?

4. 在jvm垃圾回收时被标记为可回收但还未执行回收时,java对象是什么状态?

5. jvm怎么确定 一个java对象的GC年龄?

6. 为什么对象在经历过最多15次GC后,就会被移动到老年代中?

带着上述问题,最近终于找到了答案,于是记录了下来。

在java中,一个对象是具有相关的状态的,这状态都是保存在java对象的对象头中的。本文以64位进行说明。

1. 概述

java对象由如下几部分组成:

1. 对象头:Mark word和klasspointer两部分组成,如果是数组,还包括数组长度

2. 实例属性

3. 对齐填充

java对象头信息

如何能看到上图结构?

java对象头信息

注意:要打印上述内存结构图,需要引入如下依赖:

 
   
   
   
     org.openjdk.jol 
    
   
     jol-core 
    
   
     0.9 
    
  

2. 对象头

64位对象头由Mark Word、klass pointer两部分组成,如果对象是数组,则还要加上数组长度,即三部分组成。

Mark Word由64位8个字节组成。

klass pointer由64位8个字节组成,但我们使用的64位 JVM会默认使用选项 +UseCompressedOops 开启指针压缩,将指针压缩至32位。即上面截图中的klass pointer为4个字节32位。

类指针klass pointer和数组长度,很简单这里不在描述,重点描述下Mark Word部分。

Mark Word的64位,不同的位表示的意思不一样,具体如下所示:

|--------------------------------------------------------------------------------------------------------------| | Object Header (128 bits) | |--------------------------------------------------------------------------------------------------------------| | Mark Word (64 bits) | Klass Word (64 bits) | |--------------------------------------------------------------------------------------------------------------| | unused:25 | identity_hashcode:31 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | 无锁 |----------------------------------------------------------------------|--------|------------------------------| | thread:54 | epoch:2 | unused:1 | age:4 | biased_lock:1 | lock:2 | OOP to metadata object | 偏向锁 |----------------------------------------------------------------------|--------|------------------------------| | ptr_to_lock_record:62 | lock:2 | OOP to metadata object | 轻量锁 |----------------------------------------------------------------------|--------|------------------------------| | ptr_to_heavyweight_monitor:62 | lock:2 | OOP to metadata object | 重量锁 |----------------------------------------------------------------------|--------|------------------------------| | | lock:2 | OOP to metadata object | GC |--------------------------------------------------------------------------------------------------------------|

lock:  锁状态标记位,该标记的值不同,整个mark word表示的含义不同。

biased_lock:偏向锁标记,为1时表示对象启用偏向锁,为0时表示对象没有偏向锁。

java对象头信息

age:Java GC标记位对象年龄,4位的表示范围为0-15,因此对象经过了15次垃圾回收后如果还存在,则肯定会移动到老年代中。

identity_hashcode:对象标识Hash码,采用延迟加载技术。当对象使用HashCode()计算后,并会将结果写到该对象头中。当对象被锁定时,该值会移动到线程Monitor中。

thread:持有偏向锁的线程ID和其他信息。这个线程ID并不是JVM分配的线程ID号,和Java Thread中的ID是两个概念。

epoch:偏向时间戳。

ptr_to_lock_record:指向栈中锁记录的指针。

ptr_to_heavyweight_monitor:指向线程Monitor的指针。

2.1 无锁状态时Mark Word-001

当一个对象才new且调用了hashcode方法后(如果不调用hashcode方法,那么存放hashcode的31位全部为0),正常情况下处于无锁状态,无锁状态时,Mark Word的64位分别为:前25位未使用,接下来的31位为对象的hashcode,接下来的1位未使用,接下来的4位表示对象的GC年龄,接下来的一位为偏向锁状态,最后2位表示锁状态。如下图所示:

java对象头信息

2.2 偏向锁状态时的Mark Word-101

java对象头信息

理论上而言,u对象应该是无锁状态啊,变成为偏向锁了呢?如果把sleep注释掉真的就是无锁状态。

JVM启动时会进行一系列的复杂活动,比如装载配置,系统类初始化等等。在这个过程中会使用大量synchronized关键字对对象加锁,且这些锁大多数都不是偏向锁。为了减少初始化时间,JVM默认延时加载偏向锁。这个延时的时间大概为4左右,具体时间因机器而异。当然我们也可以设置JVM参数 -XX:BiasedLockingStartupDelay=0 来取消延时加载偏向锁。

此时占用 thread 和 epoch 的 位置的均为0,说明当前偏向锁并没有偏向任何线程。此时这个偏向锁正处于可偏向状态,准备好进行偏向了!你也可以理解为此时的偏向锁是一个特殊状态的无锁

java对象头信息

2.3 轻量级锁状态时的Mark Word-000

所谓轻量级锁是指虽然代码中有synchronized关键字加锁,但jvm在执行时,不存在并发问题,这时jvm会优化成轻量级锁,如下代码所示:

public class SyncTest { public static void main(String[] args) throws Exception { final User a = new User(); Thread thread1 = new Thread(){ @Override public void run() { synchronized (a){ System.out.println("thread1 locking"); System.out.println(ClassLayout.parseInstance(a).toPrintable()); } try { //thread1退出同步代码块,且没有死亡 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread thread2 = new Thread(){ @Override public void run() { synchronized (a){ System.out.println("thread2 locking"); System.out.println(ClassLayout.parseInstance(a).toPrintable()); } } }; thread1.start(); //让thread1执行完同步代码块中方法。 Thread.sleep(3000); thread2.start(); } }

java对象头信息

2.4 重量级锁状态时的Mark Word-010

即在执行代码时真的会存在锁争抢的情况,如下代码所示:

public class SyncTest { public static void main(String[] args) throws Exception { final User a = new User(); Thread thread1 = new Thread(){ @Override public void run() { synchronized (a){ System.out.println("thread1 locking"); System.out.println(ClassLayout.parseInstance(a).toPrintable()); } try { //thread1退出同步代码块,且没有死亡 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }; Thread thread2 = new Thread(){ @Override public void run() { synchronized (a){ System.out.println("thread2 locking"); System.out.println(ClassLayout.parseInstance(a).toPrintable()); try { //thread1退出同步代码块,且没有死亡 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } } }; thread1.start(); thread2.start(); } }

java对象头信息

3.对象属性数据区

java对象头信息

int—4个字节

long–8个字节

double–8个字节

float–4个字节

short–2个字节

char–2个字节(为什么是2个字节,不应该是一个字节么?难道跟编码有关?)

Boolean–1个字节

byte–1个字节

java对象–4个字节

4. 对齐填充区

Java对象占用空间是8字节对齐的,即所有Java对象占用字节数必须是8的倍数。如下图所示:

java对象头信息

这个对象一个占用了24个字节,其中MarkWord+klasspointer+short+char+boolean+byte+对齐填充=18+对齐填充,而比18大且是8的整数倍的最小值为24,因此这个对象的对齐填充为6,整个对象大小为24字节。

对此,本章节前的几个问题就都有了答案,get get get!!!

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/201925.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月20日 上午8:17
下一篇 2026年3月20日 上午8:18


相关推荐

  • 解决JetBrains 账户连接错误,hosts下并没有0.0.0.0 account.jetbrains.com问题

    解决JetBrains 账户连接错误,hosts下并没有0.0.0.0 account.jetbrains.com问题JetBrains帐户连接错误:连接超时:连接您的主机可能在代理的后面。PhpStorm无法检测到您的代理配置。您可能希望指定HTTPS代理参数,然后重试。代理主机:代理端口:onedetermine我的hosts下面并没有0.0.0.0 account.jetbrains.com0.0.0.0www.jetbrains.com这里修改了下我本机的DNS改为 114….

    2022年8月18日
    7
  • 控制中的各种函数MATLAB仿真

    控制中的各种函数MATLAB仿真控制系统的MATLAB仿真1MATLAB简介MATLAB是Mathworks公司开发的一种集数值计算、符号计算和图形可视化三大基本功能于一体的功能强大、操作简单的优秀工程计算应用软件。MATLAB不仅可以处理代数问题和数值分析问题,而且还具有强大的图形处理及仿真模拟等功能。从而能够很好的帮助工程师及科学家解决实际的技术问题。MATLAB的含义是矩阵实验室(MatrixL

    2022年6月4日
    63
  • http://www.cnbc.com/2016/07/12/tensions-in-south-china-sea-to-persist-even-after-court-ruling.html「建议收藏」

    http://www.cnbc.com/2016/07/12/tensions-in-south-china-sea-to-persist-even-after-court-ruling.html「建议收藏」http://www.cnbc.com/2016/07/12/tensions-in-south-china-sea-to-persist-even-after-court-ruling.htmlT

    2022年7月3日
    31
  • 关于串口数据的发送和接收(调试必备)

    关于串口数据的发送和接收(调试必备)前言对于串口的数据发送和接收,大多是都是利用串口中断来进行的,但是这样对于编程方面有一定要求,并且程序也不太好写,比如说,如果让你随意接收一段数据,然后利用串口将它发送出来,第一个需要考虑的问题就是接收数据的长度,怎么才知道一段数据是否结束?或者说如果串口助手上面没有可以在数据末尾加上结束标志的时候,你如何知道数据的结束?,这必然牵涉到一定的编程技巧。但是,之前在接触C语言的时候,我们就利用过…

    2022年7月11日
    132
  • AI 提效指南:快速生成中文海报

    AI 提效指南:快速生成中文海报

    2026年3月12日
    3
  • Android开发:bindService的使用方法

    Android开发:bindService的使用方法http://blog.csdn.net/zhou_wenchong/article/details/51302574bindService用于绑定一个服务。这样当bindService(intent,conn,flags)后,就会绑定一个服务。这样做可以获得这个服务对象本身,而用startService(intent)的方法只能启动服务。   bindService方式的一般过程:

    2022年6月8日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号