我的java类读入一个60MB的文件,并生成一个包含超过3亿条记录的HashMap的HashMap。
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?
发布于 2014-04-25 23:01:25
你的数据集太大了,无法在内存中处理它,这不是最终的解决方案,只是优化。
您使用的是盒装原语,这是一件非常痛苦的事情。根据this question的说法,装箱的整数可以比未装箱的整数大20个字节。这不是我所说的内存效率。
您可以使用专门的集合对此进行优化,这些集合不会对原始值进行装箱。提供这些功能的一个项目是Trove。您可以使用TIntDoubleMap代替HashMap<Integer, Double>,也可以使用TIntObjectHashMap代替HashMap<Integer, …>。
因此,您的类型将如下所示:
TIntObjectHashMap<TIntDoubleHashMap> pairWise =
new TIntObjectHashMap<TIntDoubleHashMap>();现在,计算一下。
300.000.000个Double,每个24字节,使用7.200.000.000字节的内存,即7.2 GB。
如果您存储300.000.000个double,每个占用4个字节,那么您只需要1.200.000.000个字节,即1.2 GB。
恭喜你,你节省了大约83%的内存,你以前用来存储你的数字!
请注意,此计算是粗略的,取决于平台和实现,并且没有考虑用于HashMap/T*Map的内存。
发布于 2014-04-25 22:53:24
您的数据集足够大,因此一次将所有数据保存在内存中是不可能发生的。
考虑将数据存储在数据库中,并加载部分数据集以执行操作。
编辑:我的假设是你要对数据进行不止一次的传递。如果您所做的只是加载它并对每个项目执行一个操作,那么Lex Webb的建议(下面的注释)是比数据库更好的解决方案。如果您对每个项目执行多个操作,那么数据库似乎是更好的解决方案。数据库不需要是SQL数据库,如果您的数据是面向记录的,那么NoSQL数据库可能更合适。
发布于 2014-04-25 22:59:45
您对此卷的数据使用了错误的数据结构。Java为它创建的每个对象增加了大量的内存和时间开销--在3亿的对象级别上,您会看到大量的开销。您应该考虑将这些数据保留在文件中,并使用随机访问技术在适当的位置对其进行寻址-- take a look at memory mapped files using nio。
https://stackoverflow.com/questions/23296361
复制相似问题