目 录CONTENT

文章目录

(自用笔记)对象大小分析

MWSFOT
2023-02-06 / 0 评论 / 0 点赞 / 148 阅读 / 2,642 字

引用

JVM的指针压缩

jvm压缩指针原理以及32g内存压缩指针失效详解

需要的工具

<!--用来专门查看对象的内存布局情况-->
<dependency>
     <groupId>org.openjdk.jol</groupId>
     <artifactId>jol-core</artifactId>
     <version>0.9</version>
</dependency>
<!-- 可以告诉我们数据项分配的字节数大小 -->
<dependency>
    <groupId>com.carrotsearch</groupId>
    <artifactId>java-sizeof</artifactId>
    <version>0.0.5</version>
</dependency>

对象计算

64位JVM默认会开启指针压缩,开启后对象头占用12个字节

对象分为 对象头 + 实例数据 + 内存对齐 3部分

1.对象头

​ 而对象头又分为三部分:

​ a. Mark Word 8字节

​ 用来标记对象状态的,比如hashCode、锁状态信息等

​ b. 指向类的指针 8字节 开启指针压缩后 4字节

​ 大小也通常为32 bit, 它主要指向类的数据,也就是指向方法区中的位置

​ c. 数组长度 4字节

​ 在32位或者64位JVM中,长度都是32 bit 。数组对象才具有大小

2.实例数据

​ 指的是对象中的成员变量,如果是简单类型,则直接存对象本身,如果是非简单类型,则保存对象引用

3.内存对齐

​ 对于64位Java虚拟机来说,对象为8字节对齐,如果对象大小不满8字节的倍数,则通过该部分进行补齐

举例

普通对象
public static void main(String[] args) {
        Object obj = new Object();
        System.out.println("Obj:" + ClassLayout.parseInstance(obj).toPrintable());
 }

结果如下:

对象实类大小 = 对象头 + 实例数据 + 内存对齐
= 12B(8B mark word + 4B指向 ) + 0B实例数据 + 4B对象填充(为8倍数) 
= 16B
有实例
public class Ref {
    private int anInt;
    private byte aByte;
}

public static void main(String[] args) {
        Ref ref = new Ref();
        ref.setaByte((byte) 127);
        ref.setAnInt(127);
        System.out.println("Obj:" + ClassLayout.parseInstance(ref).toPrintable());
    }

结果如下:

对象实类大小 = 对象头 + 实例数据 + 内存对齐 =
12B(8B mark word + 4B指向 ) + 4B(int) + 1B(byte) + 7B对象填充(为8倍数)
= 24B 
增加数组对象
public class Ref {
    private int anInt;
    private byte aByte;
}
public static void main(String[] args) {
        Ref[] abc = new Ref[]{};
        System.out.println("Obj:" + ClassLayout.parseInstance(abc).toPrintable());
    }

结果如下:

可以看到增加了数组对象
对象实类大小 = 对象头 + 实例数据 + 内存对齐 =
16B(8B mark word + 4B指向 + 4B 数组对象 ) +0B 实例数据 + 0B 对象填充
= 16B
再增加数据
public class Ref {
    private int anInt;
    private byte aByte;
}
public static void main(String[] args) {
        Ref ref01 = new Ref();
        ref01.setAnInt(12);
        Ref ref02 = new Ref();
        ref01.setAnInt(13);
        Ref[] abc = new Ref[]{ref01,ref02};
        Ref[] abc = new Ref[]{ref};
        System.out.println("Obj:" + ClassLayout.parseInstance(abc).toPrintable());
    }

可以看到在数组对象的基础上增加了实例数据 多了8b
对象实类大小 = 对象头 + 实例数据 + 内存对齐 =
16B(8B mark word + 4B指向 + 4B 数组对象 ) +8B 实例数据 + 0B 对象填充
= 24B

关闭指针压缩手动添加命令

类指针压缩关闭参数为:-XX:-UseCompressedClassPointers

普通对象指针压缩关闭参数为: -XX:-UseCompressedOops

Java数据类型计算

  1. 位是计算机存储数据的最小单位, 每位存储1位的二进制0/1码, 1个字节8位(注意Bits[B] 和 bit的区别 =>字节和位), 字节是计算机处理数据的最小单位

  2. Java中的基本类型, 它们的取值范围是固定的. 且存储于栈空间中, 它们的大小不像多数语言随着机器变化而变化,是程序可移植性保证之一. 对象类型存储于堆空间中

  3. 所有的数值类型都有正负号

  4. boolean类型所占空间没有明确指定, 仅定义为能够取字面值true/false

类型 大小(字节) 最小值 最大值 范围 (开启压缩)包装类最大空间/bytes
byte 1 -128 +127 -128~127 16
short 2 -215 +215-1 - 16
int 4 -231 +231-1 - 16
long 8 -263 +263-1 - 24
float 4 IEEE754 IEEE754 - 16
double 8 IEEE754 IEEE754 - 24
char 2 Unicode o Unicode 216-1 - 16
boolean 1 - - true/false 16
堆空间大小
 public static void main(String[] args) {
         Byte a = 127;
        Integer b = 1000863231;
        Short c = 11111;
        Long d = 1111111111L;
        Float e = 100.001f;
        Double f = 200.215d;
        Character g = 'a';
        Boolean h = true;
        //计算本身在堆空间的大小 
        System.out.println(RamUsageEstimator.sizeOf(a));
        System.out.println(RamUsageEstimator.sizeOf(b));
        System.out.println(RamUsageEstimator.sizeOf(c));
        System.out.println(RamUsageEstimator.sizeOf(d));
        System.out.println(RamUsageEstimator.sizeOf(e));
        System.out.println(RamUsageEstimator.sizeOf(f));
        System.out.println(RamUsageEstimator.sizeOf(g));
        System.out.println(RamUsageEstimator.sizeOf(h));
    }

再验证类大小
 public static void main(String[] args) {
        Byte bytes = new Byte((byte) -127);
        System.out.println("Obj:" + ClassLayout.parseInstance(bytes).toPrintable());
    }

可以看到共占16 bytes  即 16个字节
对象实类大小 = 对象头 + 实例数据 + 内存对齐 =
12B(8B mark word + 4B指向 ) +1B 实例数据 + 3B 对象填充
= 16B
分析集合中情况

上面先暂时这么记, 再分析下集合中String对象的大小情况:

public static void main(String[] args) {
        List<String> refList = new ArrayList<>();
        System.out.println("oldSize:" + RamUsageEstimator.sizeOf(refList));
        System.out.println("oldClass:" + ClassLayout.parseInstance(refList).toPrintable());
        for (int i = 0; i<10; i++){
            String a = new String();
            refList.add(a);
        }

        System.out.println("newSize:" + RamUsageEstimator.sizeOf(refList));
        System.out.println("newClass:" + ClassLayout.parseInstance(refList).toPrintable());
    }

确认下集合对象各个循环结束时结果
 public static void main(String[] args) {
        List<String> refList = new ArrayList<>();
        System.out.println("oldSize:" + RamUsageEstimator.sizeOf(refList));
        System.out.println("oldClass:" + ClassLayout.parseInstance(refList).toPrintable());

        for (int i = 0; i<10; i++){
            String a = new String();
            refList.add(a);
            System.out.println(i + " : newSize:" + RamUsageEstimator.sizeOf(refList));
            System.out.println(i + " : newClass:" + ClassLayout.parseInstance(refList).toPrintable());
        }
    }
oldSize:40
oldClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     0
     16     4                  int ArrayList.size                            0
     20     4   java.lang.Object[] ArrayList.elementData                     []
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

0 : newSize:120
0 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     1
     16     4                  int ArrayList.size                            1
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), null, null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

1 : newSize:144
1 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     2
     16     4                  int ArrayList.size                            2
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), null, null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

2 : newSize:168
2 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     3
     16     4                  int ArrayList.size                            3
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), null, null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

3 : newSize:192
3 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     4
     16     4                  int ArrayList.size                            4
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), null, null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

4 : newSize:216
4 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     5
     16     4                  int ArrayList.size                            5
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), null, null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

5 : newSize:240
5 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     6
     16     4                  int ArrayList.size                            6
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), (object), null, null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

6 : newSize:264
6 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     7
     16     4                  int ArrayList.size                            7
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), (object), (object), null, null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

7 : newSize:288
7 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     8
     16     4                  int ArrayList.size                            8
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), (object), (object), (object), null, null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

8 : newSize:312
8 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     9
     16     4                  int ArrayList.size                            9
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), (object), (object), (object), (object), null]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

9 : newSize:336
9 : newClass:java.util.ArrayList object internals:
 OFFSET  SIZE                 TYPE DESCRIPTION                               VALUE
      0     4                      (object header)                           01 5c 02 18 (00000001 01011100 00000010 00011000) (402807809)
      4     4                      (object header)                           12 00 00 00 (00010010 00000000 00000000 00000000) (18)
      8     4                      (object header)                           7e 2f 00 f8 (01111110 00101111 00000000 11111000) (-134205570)
     12     4                  int AbstractList.modCount                     10
     16     4                  int ArrayList.size                            10
     20     4   java.lang.Object[] ArrayList.elementData                     [(object), (object), (object), (object), (object), (object), (object), (object), (object), (object)]
Instance size: 24 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total


Process finished with exit code 0

确认前后的数据对比
前: 集合对象所占堆空间40B, 实例大小 24B 
后: 集合空间所占堆空间336B, 实例大小24B
变量条件一致的情况下,影响的就是集合中10个String元素造成的影响
当只添加一个元素的时候大小由40B增加到120B, 而后续的循环中都是24B的步频来增加
初步判断后续的新增元素都是在第一个元素new String(空串) 的基础上类实例上新增的,而常量""都是基于第一个对象的引用
0

评论区