共计 2737 个字符,预计需要花费 7 分钟才能阅读完成。
简介
之前的文章中,咱们应用 JOL 工具简略的剖析过 String, 数组和汇合类的内存占用状况,这里再做一次更具体的剖析和介绍,心愿大家前面再遇到 OOM 问题的时候不再抱头痛哭,而是能够有章可循,开始吧。
数组
先看下 JOL 的代码和输入:
//byte array
log.info("{}",ClassLayout.parseInstance("www.flydean.com".getBytes()).toPrintable());
输入后果:
INFO com.flydean.CollectionSize - [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) 22 13 07 00 (00100010 00010011 00000111 00000000) (463650)
12 4 (object header) 0f 00 00 00 (00001111 00000000 00000000 00000000) (15)
16 15 byte [B.<elements> N/A
31 1 (loss due to the next object alignment)
Instance size: 32 bytes
Space losses: 0 bytes internal + 1 bytes external = 1 bytes total
留神,本文的论断都在 64 位的 JVM 中运行得出了,并且开启了 COOPs 压缩对象指针技术。
能够看到数组对象的对象头大小是 16 字节,再加上数组外面的内容长度是 15 字节,再加上 1 位补全。最初失去的大小是 32 字节。
同样的,咱们计算存有 100 个对象的数组,能够失去上面的论断:
留神最初面的 Object 数组,如果数组中存储的不是根底类型,那么实际上存储的是执行该对象的指针,该指针大小是 4 个字节。
String
String 是一个十分非凡的对象,它的底层是以 byte 数组存储的。
留神,在 JDK9 之前,String 的底层存储构造是 char[], 一个 char 须要占用两个字节的存储单位。
因为大部分的 String 都是以 Latin- 1 字符编码来示意的,只须要一个字节存储就够了,两个字节齐全是节约。
于是在 JDK9 之后,字符串的底层存储变成了 byte[]。
同样的咱们还是用 JOL 来剖析:
//String
log.info("{}",ClassLayout.parseInstance("www.flydean.com").toPrintable());
输入后果:
INFO com.flydean.CollectionSize - java.lang.String object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 77 1a 06 00 (01110111 00011010 00000110 00000000) (399991)
12 4 byte[] String.value [119, 119, 119, 46, 102, 108, 121, 100, 101, 97, 110, 46, 99, 111, 109]
16 4 int String.hash 0
20 1 byte String.coder 0
21 1 boolean String.hashIsZero false
22 2 (loss due to the next object alignment)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
能够看到 String 中的对象头是 12 字节,而后加上 4 字节的指针指向一个 byte 数组。再加上 hash,coder,和 hasIsZero 属性,最初的大小是 24 字节。
我这里应用的是 JDK14 的 String 版本,不同的版本可能有所不同。
当然这只是这个 String 对象的大小,不蕴含底层数组的大小。
咱们来计算一下 String 对象的实在大小:
String 对象的大小 +byte 数组的大小 =24+32=56 字节。
ArrayList
咱们构建一个非常简单的 ArrayList:
//Array List
log.info("{}",ClassLayout.parseInstance(new ArrayList()).toPrintable());
输入后果:
INFO com.flydean.CollectionSize - java.util.ArrayList object internals:
OFFSET SIZE TYPE DESCRIPTION VALUE
0 4 (object header) 05 00 00 00 (00000101 00000000 00000000 00000000) (5)
4 4 (object header) 00 00 00 00 (00000000 00000000 00000000 00000000) (0)
8 4 (object header) 87 81 05 00 (10000111 10000001 00000101 00000000) (360839)
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
画个图来直观的示意:
这里 modCount 和 size 的初始值都是 0。
HashMap
因为文章篇幅的限度,这里就不把代码列出来了,我只贴个图上来:
HashSet
LinkedList
treeMap
来个比较复杂的 TreeMap:
总结
本文用图形的模式形象的展现了汇合对象,数组和 String 在内存中的应用状况。
前面的几个汇合我就没有一一计算,有趣味的敌人能够在下方回复你计算的后果哟。
本文作者:flydean 程序那些事
本文链接:http://www.flydean.com/jvm-collections-size/
本文起源:flydean 的博客
欢送关注我的公众号: 程序那些事,更多精彩等着您!