Java利用JOL工具分析对象分布

news2024/9/29 9:23:48

对象的组成

在这里插入图片描述

对象头[Header]

  1. Markword:存储对象自身运行时数据如hashcode、gc分代年龄等,64位系统总共占用8个字节,关于Markword详细内存分布如下
    在这里插入图片描述
  2. 类型指针:对象指向类元数据地址的指针,jdk8默认开启指针压缩,64位系统占4个字节
  3. 数组长度:若对象不是数组,则不分配空间大小,若是数组,则为4个字节长度

基于上面描述数组和普通对象的对象头有不同的内存大小,主要区别在于数组长度
在这里插入图片描述

实例数据[Instance Data]

指的就是对象中各个属性大小,比如User中name和age的内存大小

public class User{
   String name;
   int age;
}

若开启了类型指针压缩,String是4个字节, int是4个字节,属性填充总共8个字节

内存对齐[Padding]

因为JVM要求java的对象占的内存大小应该是8bit的倍数,所以后面有几个字节用于把对象的大小补齐至8字节的倍数,就不特别介绍了

JOL工具分析对象

Java项目引入依赖

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

创建对象与结果分析

创建简单无锁对象

public static void main(String[] args) {
        ClassLayout classLayout = ClassLayout.parseInstance(new Object());
        System.out.println(classLayout.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

OFFSET代表内存偏移量,单位是字节
SIZE代表占用内存大小,单位字节
TYPE DESCRIPTION 类型描述,其中​​object header​​为对象头
VALUE代表存储值,对应内存中当前存储的值;

对象总大小为16个字节,对象头占用12个字节,前8个字节代表markword,对象运行时数据状态,前64位的value倒序排列拼的markword是16进制为00 00 00 00 00 00 00 01,最后一个字节01的二进制是00000001,最后三位001,代表无锁状态,后4个字节代表对象指向类元数据的指针;空对象没有属性所以实例数据不占内存,对象头+实例数据=12,不是8个倍数,所以补4个字节为16字节

enum {  locked_value              = 0, // 0 00 轻量级锁
         unlocked_value           = 1,// 0 01 无锁
         monitor_value            = 2,// 0 10 重量级锁
         marked_value             = 3,// 0 11 gc标志
         biased_lock_pattern      = 5 // 1 01 偏向锁
  };

创建有属性的对象

public class ClassLayOutCheck {
    public static void main(String[] args) {
        ClassLayout classLayout = ClassLayout.parseInstance(new User());
        System.out.println(classLayout.toPrintable());

    public static class User {
        String name;
        int age;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}

输出结果分析

org.example.object.ClassLayOutCheck$User 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)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4                int User.age                                  1
     16     4   java.lang.String User.name                                 (object)
     20     4                    (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

User对象总大小为24个字节,对象头占用12个字节,前8个字节代表markword,对象运行时数据状态,前8个字节低3位001代表无锁状,后4个字节代表对象指向类元数据的指针;User实例数据是8个字节,有属性name和age,其中name是String类型,不过这里有个问题,显示string的字节长度是4,value显示object,我们都知道内部实现是byte[],其中4字节指代对象内存指针,age是int类型,默认4个字节,value直接显示值;对象头+实例数据=20不是8字节倍数,所以填充4个字节为24个字节

创建数组

public static void main(String[] args) {
        ClassLayout classLayoutInt = ClassLayout.parseInstance(new int[]{});
        System.out.println("----------------------");
        System.out.println(classLayoutInt.toPrintable());
    }
[I 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)                           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 total

结果输出分析

对象总大小为16个字节,对象头占用16个字节,前8个字节代表markword,对象运行时数据状态,低2位00代表轻量级锁,其他位是指向栈针中锁记录的指针,4个字节代表对象指向类元数据的指针,最后4字节代表数字的长度;空数组没有属性所以实例数据不占内存,对象头+实例数据=16,是8字节的倍数,不需要填充数据

创建重量级锁对象

public static void main(String[] args) {
        User l = new User("cyl",1);
        Runnable runnable = () -> {

            synchronized (l) {

                ClassLayout layout = ClassLayout.parseInstance(l);
                System.out.println(layout.toPrintable());
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        };

        for (int i = 0; i < 3; i++) {
            new Thread(runnable).start();
        }

    }


    public static class User {
        String name;
        Integer age;

        User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
    ```
    
```java
org.example.object.ClassLayOutCheckThread$User object internals:
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
      0     4                     (object header)                           5a 1d 04 43 (01011010 00011101 00000100 01000011) (1124343130)
      4     4                     (object header)                           ab 7f 00 00 (10101011 01111111 00000000 00000000) (32683)
      8     4                     (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    java.lang.String User.name                                 (object)
     16     4   java.lang.Integer User.age                                  1
     20     4                     (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

org.example.object.ClassLayOutCheckThread$User object internals:
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
      0     4                     (object header)                           5a 1d 04 43 (01011010 00011101 00000100 01000011) (1124343130)
      4     4                     (object header)                           ab 7f 00 00 (10101011 01111111 00000000 00000000) (32683)
      8     4                     (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    java.lang.String User.name                                 (object)
     16     4   java.lang.Integer User.age                                  1
     20     4                     (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

org.example.object.ClassLayOutCheckThread$User object internals:
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
      0     4                     (object header)                           5a 1d 04 43 (01011010 00011101 00000100 01000011) (1124343130)
      4     4                     (object header)                           ab 7f 00 00 (10101011 01111111 00000000 00000000) (32683)
      8     4                     (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    java.lang.String User.name                                 (object)
     16     4   java.lang.Integer User.age                                  1
     20     4                     (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

header倒叙最后一个字节是5a,对应二进制是01011010,查看最后三位010,可知对象状态是重量级锁

创建轻量级锁对象

public static void main(String[] args) {
        User l = new User("cyl",1);
        Runnable runnable = () -> {

            synchronized (l) {

                ClassLayout layout = ClassLayout.parseInstance(l);
                System.out.println(layout.toPrintable());
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        };

        for (int i = 0; i < 1; i++) {
            new Thread(runnable).start();
        }

    }


    public static class User {
        String name;
        Integer age;

        User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }


        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }

输出结果分析

org.example.object.ClassLayOutCheckThread$User object internals:
 OFFSET  SIZE                TYPE DESCRIPTION                               VALUE
      0     4                     (object header)                           00 c9 3f 09 (00000000 11001001 00111111 00001001) (155175168)
      4     4                     (object header)                           00 70 00 00 (00000000 01110000 00000000 00000000) (28672)
      8     4                     (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4    java.lang.String User.name                                 (object)
     16     4   java.lang.Integer User.age                                  1
     20     4                     (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

header倒叙最后一个字节是00,对应二进制是00000000,查看最后三位000,可知对象状态是轻量级锁

局限性

当对象中嵌套对象时,得出Instance size这是当前对象内存大小,不是所有内存大小,比如set对象,实例属性是map,4个字节表示的对象的引用指针,而不是内部map的实际大小

java.util.HashSet 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)                           1c 72 00 f8 (00011100 01110010 00000000 11111000) (-134188516)
     12     4   java.util.HashMap HashSet.map                               (object)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

可以清楚的看到实例属性java.util.HashMap HashSet.map 的value
是object,4个字节代表它的引用指针。查询实际Java对象中嵌套对象的实际内存大小,可以自己写工具,主要就是递归直到事最基础数据类型,计算出来之后再累加,或者使用已经成熟的工具,参考博客:
两种工具查询Java嵌套对象引用内存大小

参考文章:

1.https://blog.csdn.net/superfjj/article/details/106582678
2.https://blog.51cto.com/u_15485936/5111767
3.https://blog.csdn.net/qq_38824137/article/details/107089862

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/586539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法基础学习笔记——⑫最小生成树\二分图\质数\约数

✨博主&#xff1a;命运之光 ✨专栏&#xff1a;算法基础学习 目录 ✨最小生成树 &#x1f353;朴素Prim &#x1f353;Kruskal算法 ✨二分图 &#x1f353;匈牙利算法 ✨质数 &#x1f353;&#xff08;1&#xff09;质数的判定——试除法 &#x1f353;&#xff08;2&…

简单认识OSI(计算机网络分层)七层模型

前言 学校上课讲的太笼统啥也不是&#xff0c;自己学的太玄学似懂非懂突然在看到了一篇公众文文章。文章从初始到现在&#xff0c;步步为营的遇到一个解决一个前人的问题&#xff0c;有了细致入微的讲述&#xff0c;把之前学的死东西都连起来了。 如果让你来设计网络https://m…

chatgpt赋能python:Python取余数:介绍和实际应用

Python取余数&#xff1a;介绍和实际应用 Python是一种高级编程语言&#xff0c;其灵活性和多功能性使其成为开发者的首选之一。在Python中&#xff0c;取余数是常见的数学运算之一&#xff0c;这个操作在编写程序时非常有用。在本文中&#xff0c;我们将介绍Python中的取余数…

chatgpt赋能python:Python中单行输出的使用方法

Python中单行输出的使用方法 Python是广泛使用的高级编程语言之一&#xff0c;具有易于学习、可读性强和简单易用等优点。在Python编程中&#xff0c;我们经常需要输出文本内容&#xff0c;而Python中单行输出便是一个非常重要的功能。 什么是单行输出 单行输出是指将多个元…

TDengine 深入解析缓存技术

TDengine是一款高性能的物联网大数据平台。为了高效处理时序数据&#xff0c;TDengine中大量用到了缓存技术&#xff0c;自己实现了哈希表、缓存池等技术。本文会为大家讲解TDengine中用到的这些缓存技术。 首先会介绍一下什么是缓存&#xff0c;常用的缓存技术&#xff0c;最后…

想知道怎么翻译多个文本?我教你三个好方法吧

随着电子商务的全球化发展&#xff0c;越来越多的企业意识到将产品推向全球市场的重要性。在全球市场中&#xff0c;各种语言和文化的消费者都存在着巨大的潜在需求。为了吸引和服务这些不同语言的客户&#xff0c;企业需要采取一系列的措施&#xff0c;其中翻译是至关重要的一…

科技发展的那些事儿

近30年来&#xff0c;科技发展取得了惊人的成就&#xff0c;涉及范围广泛&#xff0c;包括计算机科学、通讯技术、生物医学、能源等多个领域。本文将列举近30年来科技发展的重要事件&#xff0c;并探讨这些事件对我们的生活、工作和社会产生的影响。 1991年&#xff0c;Linux操…

chatgpt赋能python:Python中可以用八进制表示整数吗?

Python中可以用八进制表示整数吗&#xff1f; Python是一种流行的动态编程语言&#xff0c;它支持许多整数表示方法。八进制是一种表示整数的方法&#xff0c;那么Python中可以使用八进制表示整数吗&#xff1f;本文将探讨这个问题。 什么是八进制&#xff1f; 在计算机科学…

基于SSM的服装设计供需系统设计与实现

摘 要&#xff1a;作为服装设计的重要形式之一&#xff0c;服装具有显著的审美性&#xff0c;是人类情感表达不可忽视的代表形态。但在新时期背景下&#xff0c;随着服装设计的进一步优化&#xff0c;服装设计创新融合强度也随之增强。本文就服装设计供需系统进行深入探究。 服…

chatgpt赋能python:如何在Python中去掉逗号

如何在Python中去掉逗号 在Python编程中&#xff0c;逗号是一个非常常见的符号&#xff0c;它通常用于分隔多个变量或值。然而&#xff0c;有时候我们需要从文本中去掉逗号&#xff0c;以便更好地处理数据。那么在Python中&#xff0c;如何去掉逗号呢&#xff1f;接下来&#…

华为OD机试真题B卷 Java 实现【停车场车辆统计】,附详细解题思路

一、题目描述 特定大小的停车场&#xff0c;数组cars[]表示&#xff0c;其中1表示有车&#xff0c;0表示没车。 车辆大小不一&#xff0c;小车占一个车位&#xff08;长度1&#xff09;&#xff0c;货车占两个车位&#xff08;长度2&#xff09;&#xff0c;卡车占三个车位&a…

idea使用Alibaba Cloud Toolkit插件远程操作Docker

idea使用Alibaba Cloud Toolkit插件远程操作Docker 前言 从github下载的开源项目源码&#xff0c;你基本上都能在项目根目录下发现会有个Dockerfile文件&#xff0c;Dockerfile文件是记录构建docker容器的构建命令&#xff0c;用途&#xff1a;一般用来将本地的jar包远程传输到…

内存对齐原则

struct &#xff08;1&#xff09;结构体第一个数据成员放在offset为0的地方&#xff0c;后面每个成员相对于结构体首地址的偏移量&#xff08;offset&#xff09;都是成员大小&#xff08;该变量类型所占字节&#xff09;的整数倍&#xff0c;如有需要编译器会在成员之间加上填…

中国人工智能学会主办!真实AIGC业务数据驱动,欢迎全球开发者参加

近期&#xff0c;由百度商业联合中国人工智能学会举办、NVIDIA提供战略支持&#xff0c;百度飞桨承办的“百度商业AI技术创新大赛”正式启动&#xff0c;启动会现场&#xff0c;中国工程院院士、中国人工智能学会理事长、清华大学信息科学技术学院院长戴琼海院士通过视频方式对…

chatgpt赋能python:在Python中一行书写两条语句:提高代码效率的好策略

在Python中一行书写两条语句&#xff1a;提高代码效率的好策略 从一开始Python就是因为简单易用、快速开发、名字有趣等因素而受到开发者的喜爱。当然&#xff0c;解释型语言也是Python深受欢迎的原因之一&#xff0c;你可以在Linux、Windows、Mac等各种平台上运行Python脚本&…

基于SSM的图书借阅管理系统

1.项目介绍 本项目是一款基于SpringSpring MVCMybatis的图书借阅管理系统&#xff0c;主要针对计算机相关主页的正在做课程设计的学生与需要项目实战学习、练习的Java学生人群。 该系统基于B/S架构&#xff0c;采用SpringSpring MVCMybatis框架技术&#xff0c;并结合主流的轻…

一起了解AJAX

注册账号的时候账号不能重复&#xff0c;通过AJAX实现实时验证当前注册的账号是否存在。 1.1register.jsp. 1.2HomeRegisterServlet. 2.JSON概述. 2.1何为JSON. JSON即 JavaScript Object Notation &#xff08;js对象标记&#xff09; ,是一种轻量级的数据交换格式&#xf…

Eclipse教程 Ⅷ

Eclipse Debug 配置 创建和使用 Debug 配置 Eclipse Debug 配置类似于运行配置但它是用于在调试模式下开启应用。 打开 Debug 配置对话框步骤为&#xff1a;Run > Debug Configurations 。 从左侧列表中选择 "Java Application" 选项来选择要调试的 Java 代码。…

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press

使用KubeSphere3.3在Ubuntu20.04的Kubernetes1.24上部署Word Press 前言 之前已经部署了KubeSphere和K8S的基础环境&#xff1a;https://lizhiyong.blog.csdn.net/article/details/126236516 部署了大数据统一文件编排层Alluxio&#xff1a;https://lizhiyong.blog.csdn.net…

抖音seo源码开发开源--MySQL语言

源码开发是指基于开放源代码的软件或应用程序进行开发和定制。开放源代码是指软件或应用程序的源代码是公开的&#xff0c;任何人都可以查看、修改和分享。源码开发者可以从开放的源代码中学习和了解软件的工作原理&#xff0c;并基于自己的需求进行修改、定制和扩展。开放源代…