当前位置:  开发笔记 > 编程语言 > 正文

如何在Java中处理OutOfMemoryError?

如何解决《如何在Java中处理OutOfMemoryError?》经验,为你挑选了5个好方法。

我必须序列化大约一百万个项目,当我运行我的代码时,我得到以下异常:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOfRange(Unknown Source)
    at java.lang.String.(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at java.io.BufferedReader.readLine(Unknown Source)
    at org.girs.TopicParser.dump(TopicParser.java:23)
    at org.girs.TopicParser.main(TopicParser.java:59)

我该如何处理?



1> Kieron..:

理想情况下,重构代码以减少内存使用.例如,也许您可​​以流输出输出而不是将整个内容保存在内存中.

或者,只需使用该-Xmx选项为JVM提供更多内存.



2> Steve Jessop..:

我知道Java的官方答案是"哦不!出于回忆!我放弃了!".对于那些在不允许内存不足(例如,编写操作系统或为非受保护的操作系统编写应用程序)的环境中编程的人来说,这一切都令人沮丧.

投降的意愿是必要的 - 您无法控制Java内存分配的每个方面,因此您无法保证您的程序在低内存条件下成功.但这并不意味着你必须不战而降.

但是,在战斗之前,你可以寻找避免这种需要的方法.也许你可以避免Java序列化,而是定义你自己的数据格式,不需要大量的内存分配来创建.序列化分配了大量内存,因为它保留了之前看到的对象的记录,因此如果它们再次出现,它可以通过数字引用它们而不是再次输出它们(这可能导致无限循环).但这是因为它需要是通用的:根据您的数据结构,您可能能够定义一些文本/二进制/ XML /任何只能写入流的表示,而几乎不需要存储额外的状态.或者您可以安排所需的任何额外状态始终存储在对象中,而不是在序列化时创建.

如果你的应用程序执行一项使用大量内存的操作,但主要使用的内存少得多,特别是如果该操作是用户启动的,并且如果你找不到使用更少内存或提供更多内存的方法,那么它可能值得捕捉OutOfMemory.您可以通过向用户报告问题太大来恢复,并邀请他们将其修剪下来并再试一次.如果他们只花了一个小时来解决他们的问题,你就不会我只想摆脱计划并失去一切 - 你想让他们有机会为此做点什么.只要错误被捕获到堆栈中,超出的内存将在捕获错误时被取消引用,从而使VM至少有机会恢复.确保捕获常规事件处理代码下面的错误(在常规事件处理中捕获OutOfMemory会导致繁忙循环,因为您尝试向用户显示对话框,您仍然内存不足,并且您捕获另一个错误).仅在您已识别为memory-hog的操作周围捕获它,以便不会捕获来自内存耗尽以外的代码的OutOfMemoryErrors.

即使在非交互式应用程序中,放弃失败的操作也是有意义的,但是程序本身可以继续运行,处理更多数据.这就是Web服务器管理多个进程的原因,如果一个页面请求由于内存不足而失败,服务器本身就不会崩溃.正如我在顶部所说的,单进程Java应用程序无法做出任何此类保证,但它们至少可以比默认值更强大.

也就是说,您的特定示例(序列化)可能不适合这种方法.特别是,用户在被告知存在问题时可能想要做的第一件事是保存他们的工作:但如果序列化失败,则可能无法保存.这不是你想要的,所以你可能不得不做一些实验和/或计算,并在尝试序列化之前手动限制程序允许的数百万项(基于它运行的内存量).

这比尝试捕获错误并继续更强大,但不幸的是,很难找出确切的界限,所以你可能不得不谨慎一点.

如果在反序列化过程中发生错误,那么您就会更加坚定:如果您可以避免加载文件,则不应该在应用程序中出现致命错误.捕获错误更可能是合适的.

无论你做什么来处理缺乏资源(包括让错误取消应用程序),如果你关心后果,那么彻底测试它是非常重要的.困难在于你永远不知道代码中究竟会出现什么问题,因此通常需要测试大量的程序状态.


@Pacerier:它不一定是真的,但它取决于异常的来源.如果你写`try {new int [100*1024*1024]; } catch(OutOfMemoryError);`那么没有理由你不能继续.但是如果异常来自某个库,你不知道库是否已经处于稳定状态,因为如果编写它的程序员共享OOM不可恢复的观点,他们可能没有做任何努力确保代码在尝试分配内存时处于可恢复状态.

3> Mo...:

你不应该在代码中处理它.不应该捕获和处理OutOfMemory.而是使用更大的堆空间启动JVM

java -Xmx512M

应该做的伎俩.

有关详细信息,请参见此处



4> Powerlord..:

其他人已经介绍了如何为Java提供更多内存,但由于"句柄"可能意味着捕获,我将引用Sun对Errors的说法:

An Error是一个子类Throwable ,表示合理的应用程序不应该试图捕获的严重问题.大多数此类错误都是异常情况.

(强调我的)


哪里不应该意味着一定不要!+1我有几个案例我处理UnsatisfiedLinkError
如果你需要为所述线程做一些清理,ThreadDeath是你可能想要捕获的另一个.

5> Andrzej Doyl..:

您得到一个OutOfMemoryError,因为您的程序需要的内存比JVM可用的内存多.在运行时没有什么可以帮助实现的.

正如krosenvold所指出的那样,你的应用程序可能对内存提出了合理的要求,但恰好JVM没有足够的启动(例如你的应用程序将有280MB的峰值内存占用,但JVM只能以256MB开始).在这种情况下,增加分配的大小将解决这个问题.

如果您觉得在启动时提供了足够的内存,那么您的应用程序可能会暂时使用过多内存,或者内存泄漏.在您发布的情况下,听起来您正在同时持有对内存中所有百万项的引用,即使您可能正在按顺序处理它们.

检查你的参考资料对于"完成"的项目是什么样的 - 你应该尽快推荐它们,以便它们可以被垃圾收集.例如,如果要向集合中添加一百万个项目然后迭代该集合,则需要足够的内存来存储所有这些对象实例.看看你是否可以一次取一个对象,序列化它然后丢弃引用.

如果您在解决此问题时遇到问题,发布伪代码段会有所帮助.

推荐阅读
吻过彩虹的脸_378
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有