我知道每个对象都需要堆内存,堆栈上的每个原语/引用都需要堆栈内存。

当我试图在堆上创建一个对象,而内存不足时,JVM会在堆上创建一个java.lang.OutOfMemoryError,并将它抛出给我。

因此,这意味着JVM在启动时保留了一些内存。

当这个保留内存用完(它肯定会用完,请阅读下面的讨论)并且JVM在堆上没有足够的内存来创建java.lang.OutOfMemoryError实例时会发生什么?

它只是挂着吗?或者他会给我一个空,因为没有内存新的OOM实例?

try {
    Object o = new Object();
    // and operations which require memory (well.. that's like everything)
} catch (java.lang.OutOfMemoryError e) {
    // JVM had insufficient memory to create an instance of java.lang.OutOfMemoryError to throw to us
    // what next? hangs here, stuck forever?
    // or would the machine decide to throw us a "null" ? (since it doesn't have memory to throw us anything more useful than a null)
    e.printStackTrace(); // e.printStackTrace() requires memory too.. =X
}

==

为什么JVM不能预留足够的内存?

无论保留了多少内存,如果JVM没有办法“回收”内存,仍然有可能用完内存:

try {
    Object o = new Object();
} catch (java.lang.OutOfMemoryError e) {
    // JVM had 100 units of "spare memory". 1 is used to create this OOM.
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        // JVM had 99 units of "spare memory". 1 is used to create this OOM.
        try {
            e.printStackTrace();
        } catch (java.lang.OutOfMemoryError e3) {
            // JVM had 98 units of "spare memory". 1 is used to create this OOM.
            try {
                e.printStackTrace();
            } catch (java.lang.OutOfMemoryError e4) {
                // JVM had 97 units of "spare memory". 1 is used to create this OOM.
                try {
                    e.printStackTrace();
                } catch (java.lang.OutOfMemoryError e5) {
                    // JVM had 96 units of "spare memory". 1 is used to create this OOM.
                    try {
                        e.printStackTrace();
                    } catch (java.lang.OutOfMemoryError e6) {
                        // JVM had 95 units of "spare memory". 1 is used to create this OOM.
                        e.printStackTrace();
                        //........the JVM can't have infinite reserved memory, he's going to run out in the end
                    }
                }
            }
        }
    }
}

或者更简洁地说:

private void OnOOM(java.lang.OutOfMemoryError e) {
    try {
        e.printStackTrace();
    } catch (java.lang.OutOfMemoryError e2) {
        OnOOM(e2);
    }
}

当前回答

Exceptions indicating an attempt to violate the boundaries of a managed-memory environment are handled by the runtime of said environment, in this case the JVM. The JVM is its own process, which is running your application's IL. Should a program attempt to make a call that extends the call stack beyond the limits, or allocate more memory than the JVM can reserve, the runtime itself will inject an exception, which will cause the call stack to be unwound. Regardless of the amount of memory your program currently needs, or how deep its call stack, the JVM will have allocated enough memory within its own process bounds to create said exception and inject it into your code.

其他回答

JVM从来不会真正耗尽内存。它提前对堆堆栈进行内存计算。

JVM的结构,第3章,第3.5.2节说明:

如果Java虚拟机堆栈可以动态扩展,并且尝试扩展但可用内存不足 以影响扩展,或如果内存不足,可以作出 可用来创建一个新的初始Java虚拟机堆栈 线程时,Java虚拟机抛出OutOfMemoryError错误。

对于堆,请参见章节3.5.3。

如果计算需要的堆比自动存储管理系统(Java虚拟机)所能提供的多 抛出一个OutOfMemoryError。

在分配对象之前,它会提前进行计算。


JVM尝试为内存中称为永久生成区域(或PermSpace)的对象分配内存。如果分配失败(即使在JVM调用垃圾收集器尝试&分配空闲空间之后),它会抛出OutOfMemoryError。即使异常也需要内存空间,因此错误将被无限期地抛出。

进一步阅读。此外,OutOfMemoryError可能发生在不同的JVM结构中。

我非常确定,JVM将绝对确保它至少有足够的内存在内存耗尽之前抛出异常。

上次我使用Java并使用调试器时,堆检查器显示JVM在启动时分配了OutOfMemoryError实例。换句话说,它在程序有机会开始使用(更不用说耗尽)内存之前分配对象。

Exceptions indicating an attempt to violate the boundaries of a managed-memory environment are handled by the runtime of said environment, in this case the JVM. The JVM is its own process, which is running your application's IL. Should a program attempt to make a call that extends the call stack beyond the limits, or allocate more memory than the JVM can reserve, the runtime itself will inject an exception, which will cause the call stack to be unwound. Regardless of the amount of memory your program currently needs, or how deep its call stack, the JVM will have allocated enough memory within its own process bounds to create said exception and inject it into your code.

您似乎混淆了JVM保留的虚拟内存(JVM在其中运行Java程序)和主机操作系统的本机内存(JVM在其中作为本机进程运行)。您机器上的JVM运行在由操作系统管理的内存中,而不是JVM预留用于运行Java程序的内存中。

进一步阅读:

http://java.sys-con.com/node/1229281 http://publib.boulder.ibm.com/infocenter/javasdk/tools/index.jsp?topic=%2Fcom.ibm.java.doc.igaa%2F_1vg000121410cbe-1195c23a635-7ffa_1001.html

最后需要注意的是,试图捕捉java.lang.Error(及其子类)以打印stacktrace可能不会为您提供任何有用的信息。相反,您需要一个堆转储。