我正在尝试在内存中加载图像但可能有内存问题,因为我已经加载了一些其他图像。这些图像具有“可见”字段,用于指示它们是否可见。无论可见性如何,我都会将它们保存在内存中以便快速加载(当它们再次可见时)。
但是因为我在内存中有很多内容我想尝试加载新图像,如果遇到内存问题,请释放不可见的图像并重试。到目前为止,我正在使用这个相当丑陋(由于某些原因,我确定错误)代码片段:
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子句中重新捕获异常是不好的。
答案 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()非常慢(比如你正在使用数百万个对象)。通常你无论如何也不能做太多内存耗尽。