有没有可能在java中捕捉到内存exception?

我正在开发一个需要大量内存的程序,并且当内存不足exception发生时我想要捕获它。 我听说这是不可能做到的,但对于这方面是否有任何进展感到好奇。

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

可以捕捉它从Throwable下降:

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

然而,除非你正在做一些比较特殊的事情(例如在特定的代码段中分配大量的东西),否则你可能无法捕捉它,因为你不知道它将从哪里抛出。

这是可能的:

 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 } 

您可以捕获并尝试从OutOfMemoryError(OOM)exception中恢复, 但这可能是一个糟糕的想法 …尤其是如果您的目标是为了“继续前进”的应用程序。

有许多的原因:

  1. 正如其他人所指出的那样,pipe理内存资源比明确解放内存资源更好。 即使用SoftReference和WeakReference对象,如果内存很短可以释放。

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

  3. 如果问题的根本原因是内存泄漏,那么捕获和从OOM恢复的机会不会回收泄漏的内存。 你的应用程序将继续保持一段时间,然后再次,再次,并再次减less间隔。

所以我的build议是不要试图继续从一个OOM …除非你知道

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

只是把所有那些思考为什么有人可能会耗尽内存的人抛出去:我正在做一个耗尽内存的项目,我不得不为此实现一个解决scheme。

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

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

我创build了LinkedLists,Hashtables等的磁盘备份版本,这些版本都是替代它们的对象,并且实现了所有相同的接口,使得它们看起来与外部世界完全相同。

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

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

有可能捕获一个OutOfMemoryError (这是一个Error ,而不是一个Exception ),但你应该知道,没有办法得到一个定义的行为。
试图捕捉它时,甚至可能会遇到另一个OutOfMemoryError。

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

这是可能的,但如果你用完堆不是很有用。 如果有资源可以释放,那么最好使用SoftReference或WeakReference来处理这些资源,并自动进行清理。

我发现它有用,如果你用尽直接内存之前,由于某种原因不会自动触发GC。 所以如果我不能分配一个直接的缓冲区,我有原因强制一个gc。

当你正在专门分配一些可能太大的东西的时候,可能至less有一个好时机来捕捉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); } ... } 

当然,捕捉OutOfMemoryError是允许的。 确保你有一个计划什么时候发生。 在分配任何更多的对象之前,您将需要释放一些内存(通过删除对象的引用),否则您将再次耗尽内存。 有时候,仅仅几个框架的展开就可以为你做到这一点,有时你需要做更明确的事情。

有可能捕捉到任何exception。 只要写

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

理想情况下,你不应该捕获java.lang.Errorexception。 不捕捉这些exception,让应用程序终止可能是最好的解决scheme。 如果你认为你可以很好地处理这样的错误,那么继续。