• 【学习笔记】子牙教会我计算Java对象大小


    硬核子牙公众号原文:你知道如何计算Java的对象大小吗

    本文基于子牙老师的讲解,用来记录本人的理解。

    一、理论篇

    本文计算的是Java对象在 堆区 的大小。学习和掌握该知识,有助于分析“应用系统的堆到底该设置为多大?”的问题。

    接着,我整理了一张思维导图,来对对象结构中的各部分大小进行解释:

    关于实例数据区域数据大小如下表所示:

    数据类型 数据长度
    boolean 1B
    byte 1B
    char 2B
    int 4B
    float 4B
    long 8B
    double 8B
    引用类型 (开启指针压缩)4B
    (关闭指针压缩)8B

    二、猜想篇

    结合第一章《理论篇》的知识,猜想一下,在64位虚拟机下,Java对象的大小。

    目前,主流的服务器基本上都使用的是64位Java虚拟机,因此,接下来计算Java对象大小时,都以此为前提。(不考虑32位虚拟机的情况)

    2.1 Object对象大小

    Object obj = new Object();
    
    开启指针压缩 关闭指针压缩
    Mark Word 8B 8B
    Klass Pointer 4B 8B
    实例数据 0B 0B
    对齐填充 4B 0B
    合计 16B 16B

    在64位Java虚拟机下,Mark Word 都为 8B;

    开启指针压缩时,因为 8B + 4B + 0B + 0B = 12B,不符合 JVM 所有对象按 8 字节对齐的规则。因此,对象大小扩展到 16B,就可以被 8 整除了。此时,对齐填充的大小等于 4B。

    2.2 包含实例数据的对象

    public class ObjectWithInstanceData {
      private int a = 10;
      private double b = 10.0d;
    }
    
    开启指针压缩 关闭指针压缩
    Mark Word 8B 8B
    Klass Pointer 4B 8B
    实例数据 12B 12B
    对齐填充 0B 4B
    合计 24B 32B

    2.3 数组对象

    int[] array = {1,2,3};
    
    开启指针压缩 关闭指针压缩
    Mark Word 8B 8B
    Klass Pointer 4B 8B
    数组长度 4B 4B
    对齐填充(数组对象才有的) 0B 4B
    实例数据 12B 12B
    对齐填充 4B 4B
    合计 32B 40B

    三、验证篇

    3.1 指针压缩的 JVM 参数

    指针压缩的 JVM 参数:

    # 开启指针压缩(JVM默认开启的)
    -XX:+UseCompressedOops
    # 关闭指针压缩
    -XX:-UseCompressedOops
    

    3.2 借助 jol-core

    这是在代码中打印对象大小的方法。在 Maven 项目的 pom.xml 中引入依赖:

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

    打印对象大小的 API 是

    String value = ClassLayout.parseInstance(obj).toPrintable();
    System.out.println(value);
    

    我索性一口气都打印出来:

    import org.openjdk.jol.info.ClassLayout;
    
    public class ObjectWithInstanceData {
    
        private int a = 10;
        private double b = 10.0d;
    
        public static void main(String[] args) {
            Object obj = new Object();
            String value = ClassLayout.parseInstance(obj).toPrintable();
            System.out.println(value);
    
            obj = new ObjectWithInstanceData();
            value = ClassLayout.parseInstance(obj).toPrintable();
            System.out.println(value);
    
            obj = new int[]{1,2,3};
            value = ClassLayout.parseInstance(obj).toPrintable();
            System.out.println(value);
        }
    }
    

    开启指针压缩的 Object 对象结构:

    开启指针压缩的 ObjectWithInstanceData 对象结构:

    开启指针压缩的 int 数组对象结构:

    (array length) 和 (alignment/padding gap) 的 OFFSET 和 SZ 相同,占据同一块内存,因此也可以说是对齐字节为 0

    关闭指针压缩的 Object 对象结构:

    关闭指针压缩的 ObjectWithInstanceData 对象结构:

    关闭指针压缩的 int 数组对象结构:

    (array length) 和 (alignment/padding gap) 的 OFFSET 相同,从内存相同位置开始,(alignment/padding gap) SZ 比 (array length) SZ 多 4 个字节,因此也可以说是对填充齐字节为 4。

  • 相关阅读:
    cocos2dx中的精灵CCSprite
    Mark Russinovich 的博客:Windows Azure 主机更新:原因、时间和方式
    cocos2d-x中的尺寸之三
    cocos2d-x中的尺寸之二
    cocos2d-x中的尺寸之一
    cocos2d-x中的导演、场景、层和精灵
    宣布正式发布 Windows Azure 上的 Oracle 软件以及 Windows Azure Traffic Manager 更新
    Hello China操作系统STM32移植指南(三)
    Hello China操作系统STM32移植指南(二)
    diff_mysql_table_exec.py
  • 原文地址:https://www.cnblogs.com/kendoziyu/p/16536831.html
Copyright © 2020-2023  润新知