如何用代码验证对象头的存在

Java对象头的组成

Java对象的对象头由 mark word 和 klass pointer 两部分组成,

MarkWord:哈希码、GC分代年龄、锁状态标识、线程持有的锁、偏向的线程ID。

类型指针:指向类元数据指针,方法区的Class模板。

示例数据:实例数据部分就是成员变量的值,其中包括父类成员变量和本类成员变量。

对齐填充:对齐填充并不是必然存在,也没有特别的含义,它仅仅起着占位符的作用。

值得注意的是,如果应用的对象过多,使用64位的指针将浪费大量内存.64位的JVM比32位的JVM多耗费50%的内存。

我们现在使用的64位 JVM会默认使用选项 +UseCompressedOops 开启指针压缩,将指针压缩至32位。

64系统MarkWord图

以64位操作系统为例,对象头存储内容图例。
在这里插入图片描述
简单介绍一下各部分的含义

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

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

biased_lock lock 状态
0 01 无锁
1 01 偏向锁
0 00 轻量级锁
0 10 重量级锁
0 11 GC标记

age:Java GC标记位对象年龄。

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

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

epoch:偏向时间戳。

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

ptr_to_heavyweight_monitor:指向线程Monitor的指针。

验证对象头数据

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

无锁验证

package com;
import org.openjdk.jol.info.ClassLayout;

public class ObjectTest {
    
    public static void main(String[] args) {
        User p = new User();
        int hashCode = p.hashCode();
        String hex = Integer.toHexString(hashCode);
        System.out.println("HashCode十六进制:"+hex);
        print(p);
    }

    static void print(User p){
        System.err.println(ClassLayout.parseInstance(p).toPrintable());
    }
}
class User{
    private boolean a;
}

输出结果:
在这里插入图片描述
输出的第一行内容和锁状态内容对应:

unused:1|age:4|biased_lock:1|lock:2

​ 0 0000 0 01 根据MarkWord图表示User对象正处于无锁状态

第三行中表示的是被指针压缩为32位的klass pointer

第四行则是我们创建的User对象属性信息 1字节的boolean值

第五行则代表了对象的对齐字段 为了凑齐64位的对象,对齐字段占用了3个字节,24bit

至于为什么数据是倒着存储的,请参考“大小端模式”。

GC分代年龄为什么最大为15?

因为Object Header采用4个bit位来保存年龄,4个bit位能表示的最大数就是15。

验证GC垃圾回收

回收前:
在这里插入图片描述

 public static void main(String[] args) {
        User p = new User();
        int hashCode = p.hashCode();
        String hex = Integer.toHexString(hashCode);
        System.out.println("HashCode十六进制:"+hex);
        System.gc();
        print(p);
    }

回收后:
在这里插入图片描述
由于手动触发了一次GC所以四个bit位从0000变成了0001.

参照:
https://blog.csdn.net/qq_32099833/article/details/103721326

发布了60 篇原创文章 · 获赞 1 · 访问量 3324

猜你喜欢

转载自blog.csdn.net/qq_16438883/article/details/103774498