Java类的JVM调优

时间:2014-04-25 14:48:29

标签: java jvm heap-memory jvm-arguments

我的java类读取60MB文件并生成HashMapHashMap,其中包含超过3亿条记录。

HashMap<Integer, HashMap<Integer, Double>> pairWise =
                             new HashMap<Integer, HashMap<Integer, Double>>();

我已经将VM参数调整为:

-Xms512M -Xmx2048M

但系统仍然适用:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.createEntry(HashMap.java:869)
    at java.util.HashMap.addEntry(HashMap.java:856)
    at java.util.HashMap.put(HashMap.java:484)
    at com.Kaggle.baseline.BaselineNew.createSimMap(BaselineNew.java:70)
    at com.Kaggle.baseline.BaselineNew.<init>(BaselineNew.java:25)
    at com.Kaggle.baseline.BaselineNew.main(BaselineNew.java:315)

在没有OOME故障的情况下运行需要多大的堆?

3 个答案:

答案 0 :(得分:5)

您的数据集非常大,无法在内存中处理,这不是最终解决方案,只是优化。

你正在使用盒装基元,这是一个非常痛苦的事情。 根据{{​​3}},盒装整数可以比未装箱的整数大20个字节。这不是我所说的内存效率

您可以使用专门的集合对其进行优化,这些集合不会封装原始值。提供这些的一个项目是this question。您可以使用Trove代替HashMap<Integer, Double>TIntDoubleMap代替HashMap<Integer, …>

因此,您的类型将如下所示:

TIntObjectHashMap<TIntDoubleHashMap> pairWise =
                         new TIntObjectHashMap<TIntDoubleHashMap>();

现在,做数学。

300.000.000 Double s,每24个字节,使用7.200.000.000字节的内存,即7.2 GB。
如果存储300.000.000 double s,每个占用4个字节,则只需要1.200.000.000字节,即1.2 GB。 恭喜,您节省了以前用于存储数字的大约83%的内存!

请注意,此计算非常粗略,取决于平台和实现,并且不考虑用于HashMap / T * Maps 的内存。

答案 1 :(得分:3)

您的数据集足够大,不会一次将所有内容保存在内存中。

考虑将数据存储在数据库中并加载部分数据集以执行操作。

编辑:我的假设是你要对数据进行多次传递。如果您所做的只是加载它并对每个项目执行一个操作,那么Lex Webb的建议(下面的评论)是比数据库更好的解决方案。如果您为每个项目执行多个操作,那么数据库似乎是更好的解决方案。数据库不需要是SQL数据库,如果您的数据是面向记录的,那么NoSQL数据库可能更适合。

答案 2 :(得分:1)

您对此卷的数据使用了错误的数据结构。 Java为它创建的每个对象增加了内​​存和时间的显着开销 - 而在3亿对象级别,你会看到很多开销。您应该考虑将此数据保留在文件中,并使用随机访问技术来解决问题 - take a look at memory mapped files using nio

相关问题