Java查看对象的大小

1.JOL

1
2
3
4
5
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
1
2
3
4
5
6
//查看对象内部信息
print(ClassLayout.parseInstance(obj).toPrintable());
//查看对象外部信息
print(GraphLayout.parseInstance(obj).toPrintable());
//获取对象总大小
print("size : " + GraphLayout.parseInstance(obj).totalSize());

2. lucene提供的专门用于计算堆内存占用大小的工具类:RamUsageEstimator,maven坐标:

1
2
3
4
5
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>4.0.0</version>
</dependency>

常用的方法

1
2
3
4
5
6
7
8
9
//计算指定对象及其引用树上的所有对象的综合大小,单位字节
long RamUsageEstimator.sizeOf(Object obj)

//计算指定对象本身在堆空间的大小,单位字节
long RamUsageEstimator.shallowSizeOf(Object obj)

//计算指定对象及其引用树上的所有对象的综合大小,返回可读的结果,如:2KB

String RamUsageEstimator.humanSizeOf(Object obj)
1
2
3
4
5
public static void main(String[] args) {
final byte[] sLock = new byte[0];
System.out.println(RamUsageEstimator.sizeOf(new Object()));
System.out.println(RamUsageEstimator.sizeOf(sLock));
}

默认开启指针压缩 -XX:+UseCompressedOops

1
2
16
16

关闭指针压缩 -XX:- UseCompressedOops

1
2
16
24

简单好用,锁的话就用new Object()

3.关闭指针压缩为什么大了8个字节?

大了4个字节,加上要内存对齐8个字节。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
object----------------------------------------------
查看对象内部信息
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) 00 1c c3 1c (00000000 00011100 11000011 00011100) (482548736)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

查看对象外部信息
java.lang.Object@aec6354d object externals:
ADDRESS SIZE TYPE PATH VALUE
1288d8b18 16 java.lang.Object (object)


获取对象总大小
size : 16
sLock----------------------------------------------
查看对象内部信息
[B 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) a8 07 c3 1c (10101000 00000111 11000011 00011100) (482543528)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
20 4 (alignment/padding gap)
24 0 byte [B.<elements> N/A
Instance size: 24 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

查看对象外部信息
[B@41975e01d object externals:
ADDRESS SIZE TYPE PATH VALUE
1288d8b00 24 [B []


获取对象总大小
size : 24

开启指针压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
object----------------------------------------------
查看对象内部信息
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

查看对象外部信息
java.lang.Object@aec6354d object externals:
ADDRESS SIZE TYPE PATH VALUE
76be9bd30 16 java.lang.Object (object)


获取对象总大小
size : 16
sLock----------------------------------------------
查看对象内部信息
[B 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) f5 00 00 f8 (11110101 00000000 00000000 11111000) (-134217483)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 0 byte [B.<elements> N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

查看对象外部信息
[B@41975e01d object externals:
ADDRESS SIZE TYPE PATH VALUE
76be9bd20 16 [B []


获取对象总大小
size : 16

Process finished with exit code 0

4. 为什么object header 会有 20 个字节呢?

不管是否开启指针压缩,数组引用类型要多一个 4个字节的长度 的标记。

1
Object object = new Object[0x0FFFFFFF];

验证

1
2
3
4
5
6
7
8
9
10
11
12
13
object----------------------------------------------
查看对象内部信息
[Ljava.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) 38 cb 6c 1c (00111000 11001011 01101100 00011100) (476891960)
12 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
16 4 (object header) ff ff ff 0f (11111111 11111111 11111111 00001111) (268435455)
20 4 (alignment/padding gap)
24 2147483640 java.lang.Object Object;.<elements> N/A
Instance size: 2147483664 bytes
Space losses: 4 bytes internal + 0 bytes external = 4 bytes total

那我要是直接声明一个 长整型 [long]的呢?
对不起,不支持!

为什么???

Java 中数组的最大长度是多少呢?看一下它的length属性就可以了。length属性是32位的有符号整数,它的最大值是2的31次幂,就是2G。为何有这个限制呢?为什么length的属性不是long型呢?我们假设一下,如果它是long型的,那么它的最大长度是2的63次幂。内存永远也不会有那么大吧。即使是字节数组长度是int的,最大长都达到2GB.

由此想到了String,这个家伙底层也是基于数组的,是一个字符数组。字符是16位的基本类型,一个String的最大长度是多少呢?就是字符数组的最大长度也是2G,占用内存是4GB。

从JVM的角度来解释:创建数组的字节码是anewarray和newarray,操作数栈的字宽是32位,而这两个字节码的参数都是一个字长,所以无法接受long型的长度参数。不知道这样解释是否很牵强。