是否有可能在java中捕获内存不足?

时间:2009-11-07 06:37:24

标签: java exception out-of-memory

我正在开发一个需要大量内存的程序,我想在发生内存不足异常时捕获。我听说这是不可能做到的,但是如果在这方面有任何发展,我很好奇。

9 个答案:

答案 0 :(得分:83)

这不是例外;这是一个错误:java.lang.OutOfMemoryError

可以抓住它,因为它从Throwable下降:

try {
    // create lots of objects here and stash them somewhere
} catch (OutOfMemoryError E) {
    // release some (all) of the above objects
}

但是,除非你做了一些相当具体的事情(比如在特定的代码部分中分配大量的东西),否则你可能无法抓住它,因为你不知道它会被扔到哪里从

答案 1 :(得分:52)

有可能:

try {
   // tragic logic created OOME, but we can blame it on lack of memory
} catch(OutOfMemoryError e) {
   // but what the hell will you do here :)
} finally {
   // get ready to be fired by your boss
}

答案 2 :(得分:25)

您可以捕获并尝试从OutOfMemoryError(OOM)异常中恢复,但这可能是一个糟糕的想法 ...特别是如果您的目标是让应用程序“继续”。

这有很多原因:

  1. 正如其他人所指出的那样,管理内存资源的方法比明确释放内容更好;即使内存较短时可以释放的对象使用SoftReference和WeakReference。

  2. 如果等到实际耗尽内存之前你的应用程序,你的应用程序可能会花更多的时间来运行垃圾收集器。根据您的JVM版本和GC调整参数,JVM可能会越来越频繁地运行GC,因为它接近抛出OOM的点。减速(就应用程序做有用的工作而言)可能很重要。你可能想避免这种情况。

  3. 如果您的问题的根本原因是内存泄漏,那么从OOM捕获和恢复的可能性将无法回收泄漏的内存。您的应用程序将再次继续运行,然后再次,并且再次减少间隔。

  4. 所以我的建议是不要试图继续从OOM出发...除非你知道

    • OOM发生的地点和原因,
    • 不会有任何“附带损害”,
    • 恢复将释放足够的内存以继续。

答案 3 :(得分:14)

只是为那些思考为什么有人可能会耗尽内存的人抛出这个:我正在研究一个经常耗尽内存的项目,我不得不为此实现一个解决方案。

该项目是取证和调查应用程序的一个组成部分。在现场收集数据(使用非常低的内存占用,顺便说一句)后,我们的调查应用程序中会打开数据。其中一个功能是对字段中捕获的任意二进制图像(来自物理内存的应用程序)执行CFG遍历。这些遍历可能需要很长时间,但会对遍历的二进制文件产生非常有用的直观表示。

为了加快遍历过程,我们尝试尽可能多地保留物理内存中的数据,但数据结构随着二进制增长而增长,我们无法将其保留在内存中(目标是使用小于256米)。那我该怎么办?

我创建了由磁盘支持的LinkedLists,Hashtables等版本,这些是对应的替代品,并实现了所有相同的接口,因此它们看起来与外界相同。

区别?这些替换结构彼此协作,消除内存错误并请求从最近最少使用的集合中最近最少使用的元素从存储器中释放。释放元素将其转储到临时文件(在系统提供的临时目录中)中的磁盘,并在适当的集合中将占位符对象标记为“分页”。

有很多原因可能会导致java应用程序内存不足 - 大多数原因的根源是以下一项或两项: 1.应用程序在资源受限的计算机上运行(或尝试通过限制堆大小来限制资源使用) 2.应用程序只需要大量内存(建议进行图像编辑,但音频和视频怎么样?在我的情况下编译器怎么样?没有非易失性存储的长期数据收集器怎么样?)

答案 4 :(得分:8)

可以捕获OutOfMemoryError(它是Error,而不是Exception),但您应该知道,无法获得已定义的行为。<登记/> 在尝试捕获它时,您甚至可能会得到另一个OutOfMemoryError。

因此,更好的方法是创建/使用内存感知缓存。有一些框架(例如:JCS),但您可以使用SoftReference轻松构建自己的框架。有一篇关于如何使用它的文章here。按照文章中的链接获取更多信息。

答案 5 :(得分:5)

当你专门分配一些可能太大的东西时,可能至少有一次抓住OutOfMemoryError的好时机:

public static int[] decode(InputStream in, int len) throws IOException {
  int result[];
  try {
    result = new int[len];
  } catch (OutOfMemoryError e) {
    throw new IOException("Result too long to read into memory: " + len);
  } catch (NegativeArraySizeException e) {
    throw new IOException("Cannot read negative length: " + len);
  }
  ...
}

答案 6 :(得分:3)

这是可能的,但是如果你用完了它不是很有用。如果有可以释放的资源,最好将SoftReference或WeakReference用于这些资源,并且它们的清理将是自动的。

我发现如果你因为某种原因没有自动触发GC之前用完了直接内存,那么它很有用。因此,如果我未能分配直接缓冲区,我有理由强制使用gc。

答案 7 :(得分:2)

可以捕获任何异常。只需写下

try{
   // code which you think might throw exception
}catch(java.lang.Throwable t){
   // you got the exception. Now what??
}

理想情况下,您不应该捕获java.lang.Error例外。没有捕获此类异常,并且让应用程序终止可能是最佳解决方案。如果你认为你可以很好地处理这样的错误,那就继续吧。

答案 8 :(得分:1)

当然,允许捕获OutOfMemoryError。确保您有一个计划,以便在发生时做什么。在分配更多对象之前,您需要释放一些内存(通过删除对象的引用),否则您将再次耗尽内存。有时候只需几帧就可以解除堆栈的行为,有时你需要做更明确的事情。