从 java.lang.OutOfMemoryError 中恢复

Recover from java.lang.OutOfMemoryError

所以今天在学习Java的时候,终于遇到了这个特殊的错误。似乎这个错误非常普遍,试图从中恢复已经引起了不同的反应。有人认为 it is useful in certain scenarios so its a good 'good to know', some have used it in their projects, while others vehemently oppose the idea of catching this error and then a lot of others are just as confused as me.

编辑: 顺便说一句,这是我遇到的错误。我希望捕获这些错误并在下一次将 incrementor 的值减少 1/10,直到发现另一个错误
(依此类推...直到找到上限)

由于我在 Java 中处于初级阶段,找不到关于此主题的任何具体内容,因此我想就此特定示例寻求您的帮助:

public class SpeedDemoClass {
        static int iterations=0;
        static int incrementor=10000000;
    public static void main(String[] args) {
        while(incrementor>1){
            try{
              iterations=iterations+incrementor;
              iterator(iterations);
            }
            catch(Exception e){
                System.out.println("So this is the limiting error: "+e);
                iterations=iterations-incrementor;
                incrementor=incrementor/10;
                iterations=iterations+incrementor;
            }
        }
        System.out.println("The upper limit of iterations is: "+iterations);
    }

    public static void iterator(int a){
            long start_time= System.currentTimeMillis();
            StringBuilder sbuild= new StringBuilder("JAVA");
            for(int i=0;i<a;i++){
                sbuild.append("JAVA");
            }
            System.out.println("Performing "+a+" append operations;"
                    +"process completed in :"
                    +(System.currentTimeMillis()-start_time)+"ms");
    }
}

你试过编译吗?

Ofcourse, it does not work

下面是我正在尝试做的事情的简短描述!

我正在尝试执行以下操作:

  1. 初始化incrementor=10000000和iterations=0并传递incrementor=的结果增量器+迭代到 iterator().
  2. 如果出现错误,程序应捕获它,然后将 iterations* 减少 **incrementor,然后将 incrementor 除以10,然后再试一次
  3. 重复步骤 1 到 2,直到它开始工作。
  4. 目标是找到 iterations 产生错误的值,并在每次迭代后保持低于该水平,直到 iterations[= 的值上限找到 45=]
    (即当 incrementor 变为 0)

With my own manual tests, I have found out the value of this to be 92,274,686. That's the magic number. I don't know why it is so, and whether or not it is that value for my own computer only. It would be awesome if someone could post a modified code that could spit out this result.

你抓到了 Exception,但是 OutOfMemoryErrorError。注意ErrorException是Java中的两个不同的类!不过,两者都实现了 Throwable

catch子句限制了Throwable类被捕获的类型。由于 Error 不是 Exception,您的代码不会捕获 OutOfMemoryError.

内存不足通常意味着您无能为力,VM 已经崩溃。虽然看起来你可以做一些事情,比如释放内存,但 Java 会为你做所有的内存管理。您不能取消分配任何东西,您可以取消引用对象然后触发垃圾收集,但此时发生异常为时已晚。几乎任何你能做的事情都需要内存分配,而你有 none。

一般来说,VM 抛出的所有错误都无法恢复。通常是因为 VM 本身不稳定,并且您无权访问 VM 的内部来修复它。不仅如此,在极少数情况下,您的软件可以修复它。

如果您分配一些耗尽内存的额外对象、使用内存较少的 PC 等或智能分配内存,"magic number" 将会改变。 尝试估计内存消耗是一个坏主意!

相反,了解 Java 内存分配的工作原理、字符串生成器的内存布局以及如何控制它。在这里,你应该研究ensureCapacityInternal.

这个方法

查看您得到的 错误 - 特别是 类 和行号。

我敢打赌,如果你替换这一行:

StringBuilder sbuild= new StringBuilder("JAVA");

来自

StringBuilder sbuild= new StringBuilder(500000000);

然后在看到 OOM 错误之前你会走得更远。捕获这个错误并不是一个非常聪明的方法。有一些不错的变体可以观察内存消耗;但是你真的应该只在你理解了 Java 的内存组织之后才使用它们,这样你就不会得出错误的结论。

您的电脑可能有 8 GB 的内存?尝试使用 java -Xmx7500m。您可能可以达到 3 倍。因为 默认情况下,Java 只使用 25% 的内存 只是为了允许其他进程也使用一些内存。如果你想要 Java 使用你所有的内存,你必须告诉它这是需要的。

兄弟要捕获内存不足错误只需将捕获中的异常替换为内存不足错误

赶上(OutOfMemoryError e)

我打算 post 这个解决方案,但是 . Earlier this day, I seemed to have overlooked a solution presented in one of the alternative questions of this sort that I've mentioned in the beginning of

好吧,只是出于一般礼貌,这样以后的人就不会像我一样忽视一个直接面对面的解决方案,我 post 尽可能简单地回答*。这是我为实现它所做的一些小修改。看来,有可能赶上 java.lang.OutOfMemoryError 虽然我还不知道我所做的事情的含义。

* 请随时纠正我并阅读此答案的结尾 :)

I'll update this answer in the future reflecting on things that I might discover later(like discrepancies and such)

废话少说,下面是最原始的代码:

public class SpeedDemoClass {
    static int iterations=0;
    static int incrementor=10000000;
    public static void main(String[] args) {
        while(incrementor>0){
            try{
                iterations=iterations+incrementor;
                int a = iterations;
                long start_time= System.currentTimeMillis();
                StringBuilder sbuild= new StringBuilder("JAVA");
                for(int i=0;i<a;i++){
                    sbuild.append("JAVA");
                }
                System.out.println("Performing "+a+" append operations;"
                    +"process completed in :"
                    +(System.currentTimeMillis()-start_time)+"ms");
            }
            catch(OutOfMemoryError e){
                System.out.println("OutOfMemory bound reached beyond this point with error: "+e
                +"\nReverting back, and Changing the value of incrementor by 1/10th...");
                iterations=iterations-incrementor;
                incrementor=incrementor/10;
                iterations=iterations+incrementor;
            }
        }
        System.out.println("The upper limit of iterations is: "+iterations);
    }
}

Changelog:
If it is not yet apparent, I have made some tiny changes to .
(1) I ditched the method iterator() because I realize now that it made it harder for people to realize the intent of the question.
(2) I changed catch(Exception e) to catch(OutOfMemoryError e) . Turns out there is a native solution available, and I had overlooked it earlier.

输出:

它对我来说似乎很完美,现在我找到了神奇的数字。我欢迎所有可以表明这个答案是错误的评论,为什么? :)