如何避免Java中的Java堆空间异常



我正在从IO读取数据,其中包含大量数据,我需要将数据存储在Map或属性文件中的键值对中,然后只有我才能使用这些数据生成报告。但当我将这些巨大的数据存储在Map或Properties文件中时,就会出现堆内存异常。相反,如果我使用SQLLite,检索它需要花费大量的时间。有什么不同的方法可以实现这一点吗。请提出建议。

Java堆空间要点

  1. Java堆内存是操作系统分配给JVM的内存的一部分。

  2. 每当我们创建对象时,它们都是在Java的Heap中创建的。

  3. Java堆空间被划分为三个区域或代,以便于垃圾收集,称为New generation、Old或tenured generation或Perm space。永久生成是在热点JVM中的完整gc期间进行垃圾收集。

  4. 您可以使用JVM命令行选项-Xms、-Xmx和-Xmn来增加或更改Java堆空间的大小。不要忘记在指定大小后添加单词"M"或"G",以表示Mega或Gig。例如,您可以通过执行以下命令java-Xmx256mjavaClassName(您的程序类名)将java堆大小设置为258MB。

  5. 您可以使用JConsole或Runtime.maxMemory()、Runtime.totalMemory()和Runtime.freeMemory()来查询Java编程的堆大小。

  6. 您可以使用命令"jmap"获取Java中的堆转储,并使用命令"jhat"分析该堆转储。

  7. Java堆空间不同于Stack,后者用于存储调用层次结构和局部变量。

  8. Java垃圾收集器负责从死对象中回收内存并返回Java堆空间。

  9. 当你得到java.lang.OutOfMemoryError时,不要惊慌,有时这只是增加堆大小的问题,但如果它是反复出现的,那么就在java中寻找内存泄漏。

  10. 使用Profiler和堆转储分析器工具来了解Java堆空间以及为每个对象分配了多少内存。

更多详细信息参考链接:

https://docs.oracle.com/cd/E19159-01/819-3681/abeii/index.html

https://docs.oracle.com/cd/E40520_01/integrator.311/integratoretl_users/src/ti_troubleshoot_memory_errors.html

您需要粗略估计地图所需的内存。有多少键和值?键和值有多大?例如,如果键是长的,值是平均40个字符长的字符串,则20亿个键值对的绝对最小值是(40+8)*2E9-大约100 GB。当然,实际需求比最小估计值大——根据键和值的性质,可能大两倍。

如果估计的内存量超出了合理范围(除非你有很多钱,否则100GB是不合理的),你需要想办法对你的处理进行分区。你需要读入一大块数据,然后对其运行一些算法,将其缩小到较小的大小。然后对所有其他区块逐一进行处理,确保在处理新区块时不要保留旧区块。最后,查看所有块的结果并计算最终结果。为了更好地描述这种方法,请查阅"地图减少"。

如果估计的内存量有点合理(比如说,8GB,并且您有一台16GB的机器),请使用64位JVM,使用-Xmx开关设置最大堆内存,确保使用最高效的数据结构,如Trove映射。

祝你好运!

增加堆大小是一种选择,但也有一种选择可以通过使用java中的内存映射文件在堆外存储数据。您可以参考此

最新更新