当我的 java 程序启动时,它会用数千个对象填充 HashMap 。键是一个字符串,值是一组对象。
程序正在全速运行,并在达到大约 10000 个键时抛出内存不足异常:超出 GC 开销限制。
我读到可能是底层数组必须不断调整大小。但是我希望能够在不简单地增加堆大小的情况下解决这个问题。
谢谢!
最佳答案
您需要对数据大小进行建模,加上 HashMap
的每个元素开销,以确定您的堆要求。
为了简单起见,我假设您正在使用压缩的 OOPS(OOP = 普通对象指针)运行 64 位 JVM。这为每个对象提供了一个 12 字节的 header 和一个 4 字节的对象引用。我将进一步假设您正在使用默认加载因子为 0.75 的 HashMap
。
对于 10,000 个元素,表格大小最小为 10,000/0.75 = 13,333。然而,表的大小始终是 2 的幂,所以它可能有 16,384 长。这给出了 65,536 字节 -- 64KB。
存储在 HashMap
中的每个元素还需要创建一个内部 Node
对象,它有四个 4 字节的字段(hash、key、value、next)加上对象头 12 个字节,每个 Node
对象有 28 个字节。如果有 10,000 个元素,则为 280KB。
HashMap
表大小加上内部 Node
对象因此需要 344KB 的开销来存储 10,000 个键值对。那不会导致您内存不足。更改 HashMap
的初始容量将减少调整大小的复制开销,但与数百 MB 或几 GB 的典型堆大小相比,它占用的临时额外内存量可以忽略不计。
如果您的堆大小为 1 GB,并且您在 10,000 个映射条目时内存不足,那么每个键值对大约需要 100 KB。除非您大幅增加堆大小,或者减少每个键值对的大小,或者两者的某种组合,否则您将无法加载几百万个键。
关于java - 填充 Hashmap 时超出 GC 开销限制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36343813/