我的java类读取60MB文件并生成HashMap
个HashMap
,其中包含超过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故障的情况下运行需要多大的堆?
答案 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。