首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >抓到java.lang.OutOfMemoryError了?

抓到java.lang.OutOfMemoryError了?
EN

Stack Overflow用户
提问于 2010-04-20 23:11:57
回答 13查看 98.3K关注 0票数 119

文档 for java.lang.Error说:

错误是Throwable的子类,它指示合理的应用程序不应该试图捕捉的严重问题。

但是由于java.lang.Errorjava.lang.Throwable的子类,所以我可以捕获这种类型的Throwable。

我明白为什么抓到这种异常不是个好主意。据我所知,如果我们决定捕获它,catch处理程序不应该单独分配任何内存。否则,将再次引发OutOfMemoryError

所以,我的问题是:

  1. 在捕捉java.lang.OutOfMemoryError时是否有任何真实的场景可能是个好主意?
  2. 如果我们决定捕获java.lang.OutOfMemoryError,如何确保catch处理程序本身不分配任何内存(任何工具或最佳实践)?
EN

Stack Overflow用户

发布于 2011-09-09 07:29:57

OOME可以被捕获,但是它通常是无用的,这取决于JVM是否能够在到达catch块时垃圾收集一些对象,以及到那时还剩下多少堆内存。

示例:在我的JVM中,这个程序运行到完成:

代码语言:javascript
运行
复制
import java.util.LinkedList;
import java.util.List;
                
public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();
            
        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error catched!!");
        }
        System.out.println("Test finished");
    }  
}

但是,只需在catch块中添加一行就可以向您展示我所指的内容:

代码语言:javascript
运行
复制
import java.util.LinkedList;
import java.util.List;
                
public class OOMErrorTest {             
    public static void main(String[] args) {
        List<Long> ll = new LinkedList<Long>();
            
        try {
            long l = 0;
            while(true){
                ll.add(new Long(l++));
            }
        } catch(OutOfMemoryError oome){         
            System.out.println("Error caught!!");
            System.out.println("size:" +ll.size());
        }
        System.out.println("Test finished");
    }
}

第一个程序运行良好,因为当到达catch块时,JVM检测到不再使用列表(此检测也可以是编译时进行的优化)。因此,当我们到达print语句时,堆内存几乎完全被释放了,所以我们现在有很大的回旋余地可以继续。这是最好的案子。

但是,如果在捕获OOME之后使用列表ll之类的代码,则JVM无法收集它。这发生在第二个片段中。OOME是由一个新的长创建触发的,但是很快我们就创建了一个新对象( System.out.println行中的一个字符串),堆几乎已经满了,因此抛出了一个新的OOME。这是最坏的情况:我们试图创建一个新对象,失败了,我们捕获了OOME,是的,但是现在需要新堆内存的第一个指令(例如:创建一个新对象)将抛出一个新的OOME。想想看,在这一点上,我们还能做些什么呢?可能只是退出,所以我说没什么用。

JVM不是垃圾收集资源的原因之一是非常可怕的:与其他线程共享的资源也在使用它。Anyonecan看到,如果在任何类型的非实验应用中添加OOME,捕获OOME是多么危险。

我使用的是Windows x86 32位JVM (JRE6)。每个Java应用程序的默认内存为64 is。

票数 4
EN
查看全部 13 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2679330

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档