从文件加载大HashMap <string,treemap =“”>会产生java.lang.OutOfMemoryError(超出GC开销限制)</string,>

时间:2014-05-05 09:29:43

标签: java garbage-collection hashmap out-of-memory bigdata

我的问题简而言之:

  • 我的机器 500 GB RAM 没有交换(绰绰有余):top命令显示500GB的免费ram
  • 我有一个包含三元组的20GB文件(stringOfTypeX,stringOfTypeY,double val)。意思是对于一个X类型的字符串,该文件平均有20-30行,每行包含这个X类型的字符串加上一个(不同的)Y类型的字符串和相关的double值
  • 我想在内存索引HashMap中加载文件&lt; StringOfTypeX,TreeMap&lt; StringOfTypeY,val&gt; &GT;
  • 我使用BufferedReader.readLine()
  • 编写了一个Java程序
  • 在这个程序中,hashmap在构造函数中初始化,使用的initCapacity是X类型的不同字符串的预期数量的2倍(预期的键数)
  • 我使用以下程序运行程序: java -jar XXX.jar -Xms500G -Xmx500G -XX:-UseGCOverheadLimit
  • 程序似乎处理文件行的速度越来越慢:首先,它每分钟处理2M行,但是每行2M行,它会越来越慢。在16M的行之后,它几乎停止了,最终会抛出 java.lang.OutOfMemoryError(超出GC开销限制)
  • 在它抛出该错误之前,top命令显示它消耗了500GB ram的6%(并且该值是常量,程序在其生命周期的剩余时间内不会消耗更多的RAM)。
  • 我已经阅读了所有可能的互联网线程。似乎没什么用。我想GC开始做很多事情,但我不明白为什么它会这样做,因为我试图在启动前分配足够的RAM。无论如何,似乎JVM不能被迫预先分配大量的RAM,无论我给出什么命令行args。如果这是真的,那么Xmx和Xms参数的实际用途是什么?

任何人都有任何想法?非常感谢!!

更新

  • 我的jvm是64位
  • 515 GB RAM中的6.1%是~32GB。似乎JVM不允许使用超过32 GB。在this post之后,我尝试使用标志-XX:-UseCompressedOops禁用压缩指针。然而,没有任何改变。限制仍然是32GB。
  • 在任何时间点都没有进行交换(使用顶部检查)
  • 使用 -Xms400G -Xmx400G 运行无法解决问题

3 个答案:

答案 0 :(得分:2)

错误诊断这些问题是很常见的。

500 GB应该绰绰有余,假设你有超过500 GB的主内存,交换不行。

如果你有字符串,20 GB的文件可能会有很大的扩展比例。例如16个字符的字符串将使用大约80个字节的内存.A Double在64位JVM中使用大约24个字节,而不是您可能期望的8个字节。

HashMap和TreeMap每个条目使用大约24个额外字节。

使用readLine()并将容量加倍可以。实际上,预期大小* 4/3就足够了,但它总是使用下一个2的幂。

设置-Xms确实预先分配了特定的内存(或几乎是那个数字,它通常在1%的时间内没有明显的原因)

每分钟2 M线非常慢。它表明你的开销已经非常高了。我会寻找接近每秒100万行的东西。

与JVM的大小相比,1600万条目无关紧要。我的猜测是你已经开始交换了,你看到的错误是因为GC花了太长时间,而不是因为堆太满了。

你有多少免费主内存?例如在top中,您在应用程序死亡后看到了什么。

答案 1 :(得分:1)

问题解决了:

  • java -jar XXX.jar -Xms500G -Xmx500G -XX:-UseGCOverheadLimit不正确。应在 -jar 之前指定运行参数,否则它们将被视为主参数。正确的cmd行是 java -Xms500G -Xmx500G -XX:-UseGCOverheadLimit -jar XXX.jar args [0] args [1] ...

对不起,谢谢你的回答!

答案 2 :(得分:0)

你说你有500GB的RAM。您不应将Xmx设置为500 GB,因为这只是堆大小。 VM本身也有一些内存开销。所以不建议完全设置所有内存。

我建议使用例如JVisualVM来分析您的应用程序。或者让heapdump知道内存中究竟是什么。也许有些东西没有清理干净。