简体   繁体   English

填充Hashmap时,GC Overhead Limit超出

[英]GC Overhead Limit Exceeded when filling Hashmap

When my java program starts, it fills a hashmap with thousands of objects. 当我的java程序启动时,它会填充包含数千个对象的hashmap。 The key is a string and the value is a set of objects. 键是一个字符串,值是一组对象。

The program is running at full tilt and throws a Out of Memory Exception: GC Overhead Limit Exceeded when it reaches around 10000 keys. 程序全速运行并抛出内存不足异常:当GC达到10000左右时,GC超出限制超出。

I have read that it could be that the underlying array has to constantly resize. 我已经读过,可能是底层数组必须不断调整大小。 But id like to be able to solve this without simply increasing the heap size. 但是id喜欢能够在不增加堆大小的情况下解决这个问题。

Thanks! 谢谢!

You need to model the size of your data, plus the per-element overhead of HashMap , in order to determine your heap requirements. 您需要对数据的大小进行建模,再加上HashMap的每元素开销,以确定您的堆需求。

For the sake of simplicity I'll assume you're running a 64-bit JVM using compressed OOPS (OOP = ordinary object pointer). 为简单起见,我假设您使用压缩OOPS(OOP =普通对象指针)运行64位JVM。 This gives a 12-byte header per object, and a 4-byte object reference. 这为每个对象提供了一个12字节的标头,以及一个4字节的对象引用。 I'll further assume you're using a HashMap with a default load factor of 0.75. 我进一步假设您使用的HashMap的默认加载因子为0.75。

With 10,000 elements, the table size is a minimum of 10,000 / 0.75 = 13,333. 使用10,000个元素时,表格大小至少为10,000 / 0.75 = 13,333。 However, the table size is always a power of two, so it'll probably be 16,384 long. 但是,表格大小总是2的幂,所以它可能长达16,384。 That gives 65,536 bytes -- 64KB. 这给出了65,536字节 - 64KB。

Each element stored in a HashMap also requires the creation of an internal Node object, which has four 4-byte fields (hash, key, value, next) plus 12 bytes for the object header, giving 28 bytes per Node object. 存储在HashMap每个元素还需要创建一个内部Node对象,该对象有四个4字节字段(散列,键,值,下一个)加上12个字节用于对象头,每个Node对象提供28个字节。 With 10,000 elements, that's 280KB. 拥有10,000个元素,即280KB。

The HashMap table size plus the internal Node objects thus require 344KB of overhead for storing 10,000 key-value pairs. 因此, HashMap表大小加上内部Node对象需要344KB的开销来存储10,000个键值对。 That's not causing you to run out of memory. 这不会导致你内存不足。 Changing the initial capacity of the HashMap will reduce the copying overhead from resizing, but the amount of temporary extra memory it takes is negligible compared to a typical heap size of hundreds of MB or several GB. 更改HashMap的初始容量将减少调整大小时的复制开销,但与典型的数百MB或几GB的堆大小相比,它所需的临时额外内存量可以忽略不计。

If your heap size is 1 GB and you're running out of memory at 10,000 map entries, then each key-value pair takes about 100KB. 如果您的堆大小为1 GB,并且您在10,000个映射条目中的内存不足,则每个键值对大约需要100KB。 You won't be able to load a few million keys unless you drastically increase your heap size, or you reduce the size of each key-value pair, or some combination of both. 除非您大幅增加堆大小,或者减小每个键值对的大小或两者的某种组合,否则您将无法加载几百万个键。

You are geting Out of Memory because internal array is doubled each time when a certain threshold is met. 您正在进行内存不足,因为每当达到某个阈值时,内部数组会加倍。 So you need to make sure it won't be happening. 所以你需要确保它不会发生。 If you know the number of objects you need to store in the map just use constructor HashMap(int initialCapacity, float loadFactor) and provide the expected size in the first parameter. 如果您知道需要在地图中存储的对象数量,只需使用构造函数HashMap(int initialCapacity, float loadFactor)并在第一个参数中提供预期的大小。 If you don't know the number of objects you still can try to set initialCapacity so some approximate value and/or play with loadFactor parameter (default value is 0.75) - the larger the value the larger the threshold at wich there will be the resize. 如果您不知道对象的数量,您仍然可以尝试设置initialCapacity使得一些近似值和/或使用loadFactor参数(默认值为0.75) - 值越大,阈值越大,将调整大小。

You should use profilers and memory analyzer tools for performance and memory related issues. 您应该使用分析器和内存分析器工具来解决性能和内存相关问题。 One of the tips I would do is to configure JVM with flag JAVA_OPTS=-XX:-HeapDumpOnOutOfMemoryError Then when you've got this exception and JVM crashes, you may take this dump and use MAT memory analyzer tool to analyze objects distribution and root paths. 我要做的一个提示是使用标志JAVA_OPTS = -XX配置JVM:-HeapDumpOnOutOfMemoryError然后,当您遇到此异常并且JVM崩溃时,您可以使用此转储并使用MAT内存分析器工具来分析对象分布和根路径。 Also one would prefer to use Java Mission Control JMC distributed with Java and it's flight recorder. 另外,人们更愿意使用随Java分发的Java Mission Control JMC及其飞行记录器。 Please note that flight recorder is available since Java 7 update 40 请注意,自Java 7更新40以来,飞行记录器可用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM