首页 > 编程语言 >【java逆向】3分钟理清Java对象头里面的那些杂事

【java逆向】3分钟理清Java对象头里面的那些杂事

时间:2024-09-12 14:03:48浏览次数:11  
标签:School java 字节 对象 杂事 实例 Java 指针

原创 龙虾编程

对象头是一个对象用于保存自身状态的区域,在HotSpot虚拟机中,对象在堆内存中存储的布局可以划分为三个部分:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding),如下如所示:

在Java中普通对象和数组对象的对象在布局上存在一定的差异,数组对象相比普通对象多了数组长度部分,如下图所示:

1、对象头

HotSpot虚拟机对象的对象头部分可以分成mark word和类型指针两类信息,如下如所示:

(1)Mark Word:用于存储对象自身的运行时数据,如哈希码、GC分代年龄、锁状态标志等等一些信息。为了实现在极小的空间内存储尽量多的数据,Mark Word被设计成动态定义的数据结构,它可以根据对象的状态复用自己的存储空间(也就是说在运行期间Mark Word存储的数据会随着标志位的变化而变化)。如下是32位的HotSpot虚拟机中Mark Word的详细信息:

从上图可以知道一个常见的面试题目答案,为什么GC的分代年龄最大是15次了,因为分代年龄占用4位,我们知道4位二进制的可以表达的最大十位数是15。

(2)Class Pointer:指向它的类型元数据的指针,JVM通过这个指针来确定该对象是哪个类的实例。如下图所示:

(3)数组长度:如果对象是一个数组对象,那在对象头中有一块用于记录数组长度的区域,因为虚拟机可以通过普通对象的元数据信息确定对象的大小,但是如果数组的长度是不确定的,将无法通过元数据中的信息推断出数组的大小。

2、实例数据

实例数据是对象真正存储的有效信息,它记录代码里面所定义的各种类型的字段内容。
无论是从父类继承下来的,还是在子类中定义的字段都会存储到这块区域。
如下代码:

public class School {
  private int id;
  private String name;
  .....
}

实例数据部分会存储id、name的数据,如下图所示:

实例数据部分可以没有,如果一个类中没有属性也是存在的,如下所示的代码:

public class School {
 
}

此时Java对象的布局如下图所示:

所以,任何对象必须都有对象头,但是可以没有实例数据,好比火车必须要有火车头可以没有火车的车厢一样。

3、对齐填充

在Java中每8个字节做一个计数的单元,假设new了一个对象,对象占用了11个字节,11 > 8 但是又不是8的整数倍,此时这个对齐填充就会让对象变成8的整数倍,这里对齐填充补充5字节(也就是11 + 5 = (2*8) = 16)。

4、jvm中的对象的布局

public class Student{
  private int age;
  private String name;
  ......
}

public class School {
  private int id;
  private String name;
  private Student student;
  ......
}

public class TestObject{
  public static void main(String[] args){
      School school = new School(1, "龙虾编程", new Student());
  }
}

每当我们创建School对象的时候,在Java的堆中开辟内存存放对象,在栈上存放栈帧的信息,如下所示是Java对象在jvm中的布局信息:

栈帧上的局部变量表中的school指向堆空间的上的实例,对象头中的类型指针(class pointor)指向方法区的School类元信息,School中的属性数据存在到实例数据这块区域上(如果属性是对象,那么会使用指针指向其对象上)。

5、输出Java对象信息

(1)添加pom

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

(2)输出对象信息

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

输出结果:

java.lang.Object object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     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

这个结果中输出了Object对象的对象头、类型指针和对齐填充的信息,如下是对各个部分的解释图:

上面可以看出对象头是8字节,类型指针是4个字节,为什么类型指针是4字节呢?
这是因为Java中开启了指针压缩导致的。
由于对象头中mark word8字节 + 类型指针4字节 = 12字节,所以对齐填充位会自动补齐4字节,这样new Object()默认的大小是16字节。

总结:

(1)Java的对象是由对象头(mark word + class pointor + 数组长度【数组对象特有】)、实例数据和对齐填充组成的。

(2)对象必须要对象头,可以没有实例数据部分。

(3)mark word中存储了哈希码、GC信息、锁信息等等。类型指针指向方法取得类元信息上。

标签:School,java,字节,对象,杂事,实例,Java,指针
From: https://www.cnblogs.com/o-O-oO/p/18410037

相关文章

  • 全国增值税发票查验接口平台-JavaScript发票验真api示例
    全国增值税发票查验接口平台旨在优化纳税服务,加强企业发票管理,确保税收工作的准确性。企业财务可以通过发票查验接口方便快捷的验证增值税发票管理系统开具发票的真伪,以实现发票的自动化管理,减少人工操作失误,提高识别、录入、查验的准确性和工作效率,从而有效防止税务欺诈和逃......
  • Docker脚本一键打包java镜像运行备份多端口共存
    效果./docker_build.sh8081后会创建一个新的8081端口容器,并创建一个8081镜像,并备份之前的镜像可以启用多个端口 结构  DockerFile#FROM#基础镜像,当前新镜像是基于哪个镜像的#MAINTAINER#镜像维护者的姓名混合邮箱地址#RUN#容器构建时需......
  • 010-BUG: org.springframework.cglib.core.CodeGenerationException: java.lang.refle
    参考:Unabletomakeprotectedfinaljava.lang.Classjava.lang.ClassLoader.defineClass-CSDN博客1.完整报错:"msg":"org.springframework.cglib.core.CodeGenerationException:java.lang.reflect.InaccessibleObjectException-->Unabletomakeprotect......
  • 2024年金九银十最新版Java面试题及答案整理(持续更新)
    2024年金九银十到了,发现网上很多Java面试题都没有答案,所以花了很长时间搜集整理出来了这套Java面试题大全~这套互联网Java工程师面试题包括了:MyBatis、ZK、Dubbo、EL、Redis、MySQL、并发编程、Java面试、Spring、微服务、Linux、Springboot、SpringCloud、MQ、Kafka面试专......
  • Java-数据结构-二叉树-基础 (o゚▽゚)o
    文本目录:❄️一、树形结构:  ▶ 1、概念:▶ 2、特殊的概念: ▶ 3、树的表示形式:❄️二、二叉树:  ▶ 1、概念:   ▶2、两种特殊的二叉树:     ➷1)、满二叉树:      ➷ 2)、完全二叉树:  ▶3、二叉树的性质:    ➷ 1)性质一:  ......
  • 5-【JavaWeb】JUnit 单元测试及JUL 日志系统
    1.使用JUnit进行单元测试JUnit是Java中非常流行的单元测试框架,MyBatis与JUnit可以很好地结合,来测试持久层代码的正确性。1.1添加JUnit依赖在使用JUnit之前,需要在pom.xml中引入JUnit依赖。<dependency><groupId>junit</groupId><artifactId>......
  • 6- 【JavaWeb】Maven管理项目
    ApacheMaven是一个流行的构建自动化工具,用于Java项目的构建、管理和依赖处理。Maven使用XML配置文件pom.xml来管理项目的构建过程和依赖关系。1.项目结构一个标准的Maven项目结构如下:my-maven-project/├──src/│├──main/││├──java......
  • 3-【JavaWeb】Lombok配置及使用方法介绍
    Lombok入门教程1.什么是Lombok?Lombok是一个帮助简化Java类中样板代码的Java库。比如,你经常会发现自己重复编写getter和setter方法、构造函数、toString()、equals()和hashCode()方法等。Lombok通过注解来自动生成这些代码,简化开发工作。2.Lombok安装步......
  • java使用多线程
    importjava.util.concurrent.TimeUnit;importcn.hutool.core.thread.ExecutorBuilder;importcn.hutool.core.thread.ThreadFactoryBuilder;//构造多线程,可修改线程数ExecutorServiceexecutorService=ExecutorBuilder.create().setCorePoolSize(5)//初始线程......
  • 基于 Bootstrap+Echarts +Java SpringBoot 实现数字化水资源监测全景驾驶舱项目
    基于Bootstrap+Echarts+JavaSpringBoot实现数字化水资源监测全景驾驶舱项目,此项目前端采用Bootstrap前端框架,结合javaScrip和echarts以及ajax实现前端页面的展现与后端数据进行交互。后端采用JavaSpringBoot开发后台功能,对数据库增加增删改查等操作,给前端提供数据接口。......