我在一个程序中遇到这个错误,该程序创建了几个(几十万个)HashMap对象,每个对象有几个(15-20)个文本条目。在提交到数据库之前,必须收集这些字符串(不分成少量)。
根据Sun的说法,如果在垃圾收集中花费了太多时间,则会发生错误:如果将超过98%的总时间用于垃圾收集并且不到2%的堆被恢复,则OutOfMemoryError将被抛出。“。
显然,可以使用命令行将参数传递给JVM for
第一种方法工作正常,第二种方法在另一种java.lang.OutOfMemoryError中结束,这次是关于堆。
所以,问题:对于特定的用例(即几个小的HashMap对象),是否有任何编程替代方案?例如,如果我使用HashMap clear()方法,问题就会消失,但HashMap中存储的数据也会消失! : - )
中讨论答案 0 :(得分:157)
你基本上没有内存来顺利运行这个过程。想到的选项:
-Xmx512m
首先HashMap
个对象进行处理String.intern()
放在HashMap
HashMap(int initialCapacity, float loadFactor)
构造函数调整案例答案 1 :(得分:60)
以下对我有用。只需添加以下代码段:
unmovable&
致dexOptions {
javaMaxHeapSize "4g"
}
:
build.gradle
答案 2 :(得分:42)
@takrl:此选项的默认设置为:
java -XX:+UseConcMarkSweepGC
表示默认情况下此选项不活动。所以当你说你使用了这个选项
“+XX:UseConcMarkSweepGC
”
我假设您使用的是这种语法:
java -XX:+UseConcMarkSweepGC
表示您明确激活了此选项。
有关Java HotSpot VM Options
@ this的正确语法和默认设置
document
答案 3 :(得分:23)
为了记录,我们今天遇到了同样的问题。我们使用此选项修复了它:
-XX:-UseConcMarkSweepGC
显然,这修改了用于垃圾收集的策略,这使问题消失了。
答案 4 :(得分:12)
完全重新考虑您的算法&数据结构,因此它不需要所有这些小HashMaps。
创建一个外观,允许您根据需要在内存中分页HashMaps。一个简单的LRU缓存可能就是故障单。
向上提供JVM可用的内存。如果你有管理这台野兽的机器,即使购买更多的RAM也可能是最快,最便宜的解决方案。话虽如此:我通常不是“投入更多硬件”解决方案的粉丝,特别是如果可以在合理的时间范围内考虑替代算法解决方案。如果你不断在每一个问题上投入更多的硬件,你很快就会遇到收益递减规律。
你到底想要做什么?我怀疑你的实际问题有更好的方法。
答案 5 :(得分:9)
答案 6 :(得分:9)
在等待结束时,不要将整个结构存储在内存中。
将中间结果写入数据库中的临时表而不是hashmaps - 从功能上讲,数据库表相当于hashmap,即两者都支持键控访问数据,但表不受内存限制,因此使用索引表这里而不是哈希图。
如果操作正确,您的算法甚至不应该注意到更改 - 这里正确意味着使用类来表示表,甚至给它一个put(键,值)和get(key)方法就像一个hashmap。
中间表完成后,从中生成所需的sql语句,而不是从内存中生成。
答案 7 :(得分:8)
如果在垃圾收集中花费了太多时间,并行收集器将抛出OutOfMemoryError
。特别是,如果超过98%的总时间花在垃圾收集上,并且回收的堆少于2%,则会抛出OutOfMemoryError
。此功能旨在防止应用程序长时间运行,同时由于堆太小而很少或没有进度。如有必要,可以通过在命令行中添加选项-XX:-UseGCOverheadLimit
来禁用此功能。
答案 8 :(得分:5)
如果您正在创建数十万个哈希映射,那么您可能使用的远远超过实际需要;除非您使用大型文件或图形,否则存储简单数据不应超出Java内存限制。
您应该尝试重新考虑您的算法。在这种情况下,我会就该主题提供更多帮助,但在您提供有关问题背景的更多信息之前,我无法提供任何信息。
答案 9 :(得分:5)
如果您有 java8 ,并且可以使用 G1垃圾收集器,请运行您的应用程序:
-XX:+UseG1GC -XX:+UseStringDeduplication
这告诉G1找到类似的字符串,只保留其中一个在内存中,其他只是指向内存中String的指针。
当你有很多重复的字符串时,这很有用。此解决方案可能或不起作用,取决于每个应用程序。
更多信息:
https://blog.codecentric.de/en/2014/08/string-deduplication-new-feature-java-8-update-20-2/
http://java-performance.info/java-string-deduplication/
答案 10 :(得分:3)
使用JDK 1.7.x
或更高版本,使用G1GC
, ,其垃圾收集费用为10%,而其他GC算法则为2%。 < / p>
除了使用-Xms1g -Xmx2g
设置堆内存外,请尝试`
-XX:+UseG1GC
-XX:G1HeapRegionSize=n,
-XX:MaxGCPauseMillis=m,
-XX:ParallelGCThreads=n,
-XX:ConcGCThreads=n`
查看oracle文章,了解这些参数的微调。
与SE中的G1GC有关的一些问题:
Java 7 (JDK 7) garbage collection and documentation on G1
答案 11 :(得分:2)
如果出现错误:
“内部编译器错误:java.lang.OutOfMemoryError:java.lang.AbstractStringBuilder超出了GC开销限制”
将java堆空间增加到2GB,即-Xmx2g.
答案 12 :(得分:2)
您需要在Jdeveloper中增加内存大小,转到setDomainEnv.cmd。
set WLS_HOME=%WL_HOME%\server
set XMS_SUN_64BIT=256
set XMS_SUN_32BIT=256
set XMX_SUN_64BIT=3072
set XMX_SUN_32BIT=3072
set XMS_JROCKIT_64BIT=256
set XMS_JROCKIT_32BIT=256
set XMX_JROCKIT_64BIT=1024
set XMX_JROCKIT_32BIT=1024
if "%JAVA_VENDOR%"=="Sun" (
set WLS_MEM_ARGS_64BIT=-Xms256m -Xmx512m
set WLS_MEM_ARGS_32BIT=-Xms256m -Xmx512m
) else (
set WLS_MEM_ARGS_64BIT=-Xms512m -Xmx512m
set WLS_MEM_ARGS_32BIT=-Xms512m -Xmx512m
)
and
set MEM_PERM_SIZE_64BIT=-XX:PermSize=256m
set MEM_PERM_SIZE_32BIT=-XX:PermSize=256m
if "%JAVA_USE_64BIT%"=="true" (
set MEM_PERM_SIZE=%MEM_PERM_SIZE_64BIT%
) else (
set MEM_PERM_SIZE=%MEM_PERM_SIZE_32BIT%
)
set MEM_MAX_PERM_SIZE_64BIT=-XX:MaxPermSize=1024m
set MEM_MAX_PERM_SIZE_32BIT=-XX:MaxPermSize=1024m
答案 13 :(得分:2)
对于此用法,请在android闭包下的app gradle文件中使用代码。
dexOptions { javaMaxHeapSize“4g” }
答案 14 :(得分:1)
对于我的情况,使用-Xmx
选项增加内存是解决方案。
我在java中读取了10g文件,每次出现同样的错误。当RES
命令中的top
列中的值达到-Xmx选项中设置的值时,会发生这种情况。然后通过使用-Xmx
选项增加内存,一切都很顺利。
还有另外一点。当我在用户帐户中设置JAVA_OPTS
或CATALINA_OPTS
并再次增加内存量时,我得到了同样的错误。然后,我在我的代码中打印了那些环境变量的值,这给了我不同于我设置的值。原因是Tomcat是该进程的根,然后因为我不是su-doer,我要求管理员增加Tomcat中catalina.sh
的内存。
答案 15 :(得分:0)
这有助于我摆脱这个错误。此选项禁用 -XX:+ DisableExplicitGC