我有一个包含 1000 个字符串的哈希集。每个字符串的大小为 10。
你能告诉我将其存储在内存中所需的确切字节数吗?适用于 32 位和 64 位 VM。
你能解释一下这个的计算方法吗?
最佳答案
因为我没有生活,所以我呈现无聊的结果。请注意,由于愚蠢的错误等原因,这几乎可以保证是不准确的。二手this寻求帮助,但我不太确定准确性。我可以阅读 JVM 规范,但我没有那么空闲时间。
由于关注的对象内部存在大量字段,而且我对对象的开销有多少以及填充的位置存在一些不确定性,因此该计算变得相当复杂。如果没记错的话,对象有 8 个字节保留给 header 。顺便说一句,这都是针对 64 位 VM 的。我认为,它与 32 位 VM 之间的唯一区别是引用的大小。
做法总结:获取源码,递归累加所有字段所需空间。需要了解 VM 如何工作以及实现如何工作。
从 String
开始. String
定义:
- 对象头 - 8 字节
-
long serialVersionUID
- 8 个字节 -
int hash
- 4 字节 + 4 字节填充 -
char[] value
(在您的情况下设置为char[10]
)- 8 个字节供引用 -
ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]
- 8字节供引用
char[10]
定义:
- 对象头 - 8 字节
-
int length
- 4 个字节 -
char
x10 - 2 字节 * 10 = 20 字节
ObjectStreamField[0]
定义:
- 对象头 - 8 字节
-
int length
- 4 字节 + 4 字节填充
单个总计String
长度为 10:88 字节
总计 1000 String
长度为 10 的 s:88000 字节。
HashSet
定义:
- 对象头 - 8 字节
-
long serialVersionUID
- 8 个字节 -
Object PRESENT
- 8 个字节 -
HashMap<E, Object> map
- 8 个字节
HashMap
定义(在 Java 8 中)(忽略按需创建的内容,例如 EntrySet
):
- 对象头 - 8 字节
-
long serialVersionUID
- 8 个字节 -
int DEFAULT_INITIAL_CAPACITY
- 4 个字节 -
int MAXIMUM_CAPACITY
- 4 个字节 -
int TREEIFY_THRESHOLD
- 4 个字节 -
int UNTREEIFY_THRESHOLD
- 4 个字节 -
int MIN_TREEIFY_CAPACITY
- 4 个字节 -
int size
- 4 个字节 -
int modcount
- 4 个字节 -
int threshold
- 4 个字节 -
float DEFAULT_LOAD_FACTOR
- 4 个字节 -
float loadFactor
- 4 个字节 -
Node<K, V>[] table
- 8 个字节
Node
定义:
- 对象头 - 8 字节
-
int hash
- 4 字节 + 4 字节填充 -
K key
- 8 个字节 -
V value
- 8 个字节 -
Node<K, V> next
- 8 个字节
Node<K, V>[]
如果我记得 HashMap
应该有 2048 的大小作品。所以它定义了:
- 对象头 - 8 字节
-
int length
- 4 字节 + 4 字节填充 -
Node<K, V>
引用 * 2048 - 8 字节 * 2048 = 16384 字节。
所以 HashSet
应该是:
- 32 字节仅用于
HashSet
- 仅
HashMap
为 64 字节 - 每个
Node<K, V>
40 个字节里面Node<K, V>[]
* 1000 个节点 = 40000 字节 - 16400 字节
Node<K, V>[]
在HashMap
里面
总计:HashSet
的 56496 字节, 不考虑 String
内容
所以至少根据我的计算,占用的总空间应该在 144496 字节左右——大约 141 KB(迂腐的是 kibibytes)。老实说,这似乎有点小,但这是一个开始。
我无法获得 Instrumentation
界面目前正在工作,所以我无法仔细检查。但是,如果有人知道他/她在做什么,欢迎发表评论指出我的错误。
关于一组字符串的Java对象内存大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24253710/