当我的Java程序启动时,它将用数千个对象填充哈希图。键是一个字符串,值是一组对象。
程序以完全倾斜的方式运行,并且出现内存不足异常:达到10000个密钥时,超出了GC开销限制。
我读过,可能是底层数组必须不断调整大小。但是id希望能够解决此问题而不必简单地增加堆大小。
谢谢!
最佳答案
您需要对数据大小进行建模,再加上HashMap
的每个元素的开销,以便确定您的堆需求。
为了简单起见,我假设您正在使用压缩的OOPS(OOP =普通对象指针)运行64位JVM。这样就为每个对象提供了12个字节的标题,并为对象提供了4个字节的引用。我进一步假设您使用的HashMap
的默认加载因子为0.75。
对于10,000个元素,表大小最小为10,000 / 0.75 = 13,333。但是,表的大小始终是2的幂,因此它的长度可能为16,384。给出65,536字节-64KB。
存储在HashMap
中的每个元素还需要创建一个内部Node
对象,该对象具有四个4字节字段(哈希,键,值,下一个),外加12个字节的对象头,每个Node
28个字节>对象。拥有10,000个元素,即280KB。
因此,HashMap
表大小加上内部Node
对象需要344KB的开销才能存储10,000个键值对。这并不会导致您的内存不足。更改HashMap
的初始容量将减少调整大小的复制开销,但是与通常的数百MB或几GB的堆大小相比,其占用的临时额外内存量可以忽略不计。
如果堆大小为1 GB,并且10,000个映射条目的内存不足,则每个键值对大约需要100KB。除非您急剧增加堆大小,或者减小每个键值对的大小,或者减小两者的某种组合,否则您将无法加载数百万个键。