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

这篇具有很好参考价值的文章主要介绍了Java利用JOL工具分析对象分布。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

对象的组成

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

对象头[Header]

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

基于上面描述数组和普通对象的对象头有不同的内存大小,主要区别在于数组长度
Java利用JOL工具分析对象分布

实例数据[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文章来源地址https://www.toymoban.com/news/detail-472016.html

到了这里,关于Java利用JOL工具分析对象分布的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java反射】Java利用反射获取和设置对象某属性的值

    通用工具类: 测试:

    2024年02月02日
    浏览(57)
  • 利用Java代码调用Lua脚本改造分布式锁

    4.8 利用Java代码调用Lua脚本改造分布式锁 lua脚本本身并不需要大家花费太多时间去研究,只需要知道如何调用,大致是什么意思即可,所以在笔记中并不会详细的去解释这些lua表达式的含义。 我们的RedisTemplate中,可以利用execute方法去执行lua脚本,参数对应关系就如下图股

    2024年04月10日
    浏览(55)
  • 利用GAT(图论分析工具箱)构建并分析大脑结构协变网络学习笔记

    前面我学习了利用DTI构建白质纤维脑网络,并采用GRETNA计算了小世界网络属性。阅读文献发现可以利用灰质体积或皮层指标(皮层厚度、折叠指数、沟深)等构建结构协变网络再进行网络拓扑属性的计算。因此,我采用前面提取的灰质体积和皮质数据进行了结构协变网络分析

    2024年04月16日
    浏览(101)
  • 利用大数据分析工具,实现多场景可视化数据管理

    https://yanhuang.yuque.com/staff-sbytbc/rb5rur? 购买服务器 购买腾讯云服务器,1300 元新人价,一年时间 ●4核16G内存 ●CentOS 6.7 (补充说明:最新的 2.7.1 GA 版本,8G 内存也是可以跑的,可以先使用8G,不够再做升级)。 安装docker环境 安装docker,速度还挺快的,大概3~5分钟内 1、注册鸿

    2024年02月14日
    浏览(58)
  • Java中利用Redis,ZooKeeper,数据库等实现分布式锁(遥遥领先)

    1.1 什么是分布式锁 在我们进行单机应用开发涉及并发同步的时候,我们往往采用synchronized或者ReentrantLock的方式来解决多线程间的代码同步问题。但是当我们的应用是在分布式集群工作的情况下,那么就需要一种更加高级的锁机制,来处理种跨机器的进程之间的数据同步问题

    2024年02月03日
    浏览(51)
  • 计算机组成原理课程论文:分布式存储系统组成和应用

    摘要 分布式存储系统是一种解决大规模数据处理和存储需求的重要技术。本文首先对分布式存储系统进行了概述,包括其定义、优缺点等。然后,详细介绍了分布式存储系统的组成部分,包括存储节点、数据管理软件、网络连接和元数据管理,并结合具体案例进行了说明。接

    2024年02月13日
    浏览(66)
  • Java对象逃逸及逃逸分析

    文章目录 前言 一、对象逃逸是什么? 1.1 概念 1.2 代码分析 二、逃逸分析(一种分析算法) 1.什么是逃逸分析 2.代码优化实践 2.2 同步锁消除 2.3 标量替换分析 总结 随着 JIT 编译器的发展与逃逸分析技术逐渐成熟, 栈上分配、标量替换优化 技术将会导致一些微妙的变化,所有的

    2024年02月05日
    浏览(33)
  • 【工具】java工具 xml字符串转json对象

    //json字符串

    2024年02月07日
    浏览(49)
  • HadoopHA模式(由于Hadoop的HA模式是在Hadoop完全分布式基础上,利用zookeeper等协调工具配置的高可用的Hadoop集群模式)

    目录 1.前期准备 1.1.hadoop-3.1.3.tar.gz,jdk-8u212-linux-x64.tar.gz,apache-zookeeper-3.5.7-bin.tar.gz三个包提取码:k5y6 2.解压安装包,配置环境变量 3. 将三个节点分别命名为master、slave1、slave2并做免密登录 免密在前面Hadoop完全分布式搭建说过,这里不再赘述 4.搭建zookeeper集群  根据配置的

    2024年02月04日
    浏览(43)
  • Java安全之SnakeYaml漏洞分析与利用

    SnakeYaml是Java中解析yaml的库,而yaml是一种人类可读的数据序列化语言,通常用于编写配置文件等。 yaml基本语法 : 大小写敏感 使用缩进表示层级关系 缩进只允许使用空格 # 表示注释 支持对象、数组、纯量这3种数据结构 示例 yaml对象: yaml数组: 意思是 companies 属性是一个数

    2024年02月04日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包