我在研究 Hash Map 的内部结构时遇到了以下细节:
实现是一个 HashMap$Entry 对象的数组:
每个 HashMap$Entry 包含: – int key 哈希 – 下一个对象 – 对象键 – 对象值
默认容量为 16 个条目
空大小为128字节
HashMap 的开销是 48 字节,加上 (16 + (entries * 4bytes)) array – 加上 HashMap$Entry 对象的开销
每个键 ↔ 值条目额外 32 字节 HashMap 的开销是
因此:– 48 字节,加上每个条目 36 字节
谁能解释一下“HashMap 的开销是 48 字节,加上 (16 + (entries * 4bytes))
array" 和 "每个 key ↔ value entry 额外 32bytes HashMap 的开销是
因此:– 48 字节,加上每个条目 36 字节” ???
我不明白这些结论是如何得出的,即我们是如何发现关于 HashMap 的最终内存细节的。
最佳答案
You might want to read this SO question.对象开销在不同的 CPU 架构、VM 实现和不同的 Java 版本之间会有所不同(例如 OOPS,也有建议 fixnums 等)。
But let's see for ourselves对于 OpenJDK 7,HashMap
类:
Overhead is 48 bytes for
HashMap
客房服务信息。 大概是 8 个字节。
实现中有三个字段,用于保存由 keySet()
、values()
和 entrySet()
方法生成的 View 。三个指针,在 32 位机器上是 12 个字节。
// from AbstractMap
transient volatile Set<K> keySet = null;
transient volatile Collection<V> values = null;
// from HashMap
private transient Set<Map.Entry<K,V>> entrySet = null
共有三个int
字段:size
、threshold
和modCount
。 12 个字节。
有一个float
字段:loadFactor
。 4 个字节。
表指针本身(Entry[] 表
)。 4 个字节。
(static final
字段不算在内,它们是编译时常量)
所有这些都为我们提供了 40 字节 HashMap
实例的固定成本。它不是 48 字节,我不知道为什么。也许我错过了什么,也许你的文字提到了其他版本。这些事情有时会发生一些变化。过去可能有一个额外的字段。也许它从 40 字节填充到 48 字节(但它不应该)。
16 + (entries * 4 bytes) for array
Entry[]表
表是在构造HashMap
时实例化的,我们也需要对它进行计数。
一个实例化的数组需要 8 个字节 的管理数据,4 个字节
用于length
属性。那是 12 个字节,而不是 16 个。同样,不知道它来自哪里。
每个条目都是指向 Entry
对象的指针,因此每个条目 4 个字节。这很容易。
Additional 32 bytes per key ↔ value entry
同样,8 字节的内务处理。
现在,字段:
final K key; // a reference, 4 bytes
V value; // a reference, 4 bytes
Entry<K,V> next; // a reference, 4 bytes
final int hash; // an integer primitive, 4 bytes
16 个字节。
这是每个条目的最终计数 24 字节。同样,这不是 36。
我不知道你那里的数字是从哪里来的。那可能是 IBM 虚拟机吗?那可能是 64 位操作系统吗?也许现在的管家信息是 16 个字节(Java 8 会改变什么吗?)。
无论如何,我尝试尽我所知计算内存消耗。
关于java - HashMap 内存开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20175225/