处理这种“尝试 - 错误 - 清洁 - 重审”案件的最佳方法是什么?

时间:2009-09-02 21:05:53

标签: java memory memory-management

我正在尝试在内存中加载图像但可能有内存问题,因为我已经加载了一些其他图像。这些图像具有“可见”字段,用于指示它们是否可见。无论可见性如何,我都会将它们保存在内存中以便快速加载(当它们再次可见时)。

但是因为我在内存中有很多内容我想尝试加载新图像,如果遇到内存问题,请释放不可见的图像并重试。到目前为止,我正在使用这个相当丑陋(由于某些原因,我确定错误)代码片段:

try {
    image = GraphicsUtilities.loadImage(filePath);
} catch (OutOfMemoryError e) {
    removeHiddenImageReferences();
    try {
        image = GraphicsUtilities.loadImage(filePath);
    } catch (OutOfMemoryError ee) {
        ee.printStackTrace();
        JOptionPane.showMessageDialog(parent,
            "There is not enought memory to load this image",
            "Not enough memory", JOptionPane.WARNING_MESSAGE);
    }
}

我的问题是,我该如何处理这种情况?我觉得捕获异常并在catch子句中重新捕获异常是不好的。

6 个答案:

答案 0 :(得分:4)

我不认为这是特别糟糕的风格 - “catch”子句的重点是处理异常的原因。在这种情况下,您选择通过释放一些来处理内存不足,然后在传播错误之前允许进一步重试。看起来非常合理 - 你可以用任何语法扭曲的方式重写它,以避免在catch子句中包含代码,但为什么要这么麻烦?这清楚地表达了你的意图。

然而,一个可能有意义的设计更改是在第二种情况下重新抛出异常(或者,只是不捕获它),并且有一个更全局的异常处理程序来处理完整的内存。即使这是有争议的 - 如果你真的不期望任何其他OutOfMemory情况,那么处理它接近(几乎)总是导致它的情况是合理的。

答案 1 :(得分:3)

这是一个艰难的问题,因为OutOfMemoryError并非针对个别Threads。这意味着虽然在当前Thread中您正在加载占用进程内存大部分的映像,但另一个Thread可能正在运行实际触发OutOfMemoryError的进程。如果你需要在进程中处理这个案例,Adam Wright想要一个更全球化的OOME经理是值得考虑的。

编辑:

This article讨论了如何设置内存警告系统,以便在触发OOME之前可以提醒监听器。这使您可以采取预防措施,并从衰弱的OOME中保存您的系统。阅读完你的评论后,我发布的链接是为了后人。

答案 2 :(得分:2)

一种选择是将其分解为2种方法,调用LoadImage在内部调用TryLoadImage。

public void TryLoadImage(string filePath){
     bool b = false;

     try{
          image = GraphicsUtilities.loadImage(filePath);
          bool b = true;
     }
     catch(OutOfMemoryError){
          // Log notfication of file the was too big perhaps? so in the future you could
          // optimize this?  
     }
}

public void LoadImage(string filePath, bool clearReferences){

      if(!TryLoadImage(string filePath))    
      {
            removeHiddenImageReferences();
            if(!TryLoadImage(string filePath)){
                   // Log error
                   JOptionPane.showMessageDialog ....
            }
      }
}

答案 3 :(得分:1)

引入一个while循环,使你的重试逻辑与一个条件联系在一起,而不仅仅是抛出的异常。

int tryCount = 2;
while (tryCount > 0) {
  try {
    image = GraphicsUtilities.loadImage(filePath);
  } catch (OutOfMemoryError e) {
    removeHiddenImageReferences();
    tryCount--;
  }
}
if(tryCount <= 0) {
        JOptionPane.showMessageDialog(parent,
            "There is not enought memory to load this image",
            "Not enough memory", JOptionPane.WARNING_MESSAGE);
}

此示例错过了堆栈跟踪,但此时它并不重要,因为您的内存不足(只需在MessageDialog中包含一个标识符或进行此项检查的日志)。

答案 4 :(得分:1)

您是否考虑过使用SoftReference?虽然它不一定会在这里改变你的代码,但是如果你的应用程序正在做其他事情,它会使情况更具可扩展性,如果它在其他地方内存不足,你会愿意抛弃这些图像。

答案 5 :(得分:-1)

你可以打电话

removeHiddenImageReferences();

第一。然后你只需要一次尝试/捕获。优化是没有用的,除非你知道removeHiddenImageReferences()非常慢(比如你正在使用数百万个对象)。通常你无论如何也不能做太多内存耗尽。