我知道每个对象都需要堆内存,堆栈上的每个原语/引用都需要堆栈内存.
当我尝试在堆上创建一个对象并且没有足够的内存来执行此操作时,JVM会在堆上创建一个java.lang.OutOfMemoryError并将其抛给我.
所以隐含地,这意味着JVM在启动时保留了一些内存.
当这个保留的内存用完时会发生什么(它肯定会用完,下面的讨论),而且JVM上没有足够的内存来创建java.lang.OutOfMemoryError的实例?
它只是挂起来吗?或者他会抛弃我,null
因为new
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 …
Run Code Online (Sandbox Code Playgroud) 在什么情况下应该抓住java.lang.Error
应用程序?
Web服务返回一个巨大的XML,我需要访问它的深层嵌套字段.例如:
return wsObject.getFoo().getBar().getBaz().getInt()
Run Code Online (Sandbox Code Playgroud)
问题是getFoo()
,getBar()
,getBaz()
可能所有的回报null
.
但是,如果我null
在所有情况下检查,代码将变得非常冗长且难以阅读.此外,我可能会错过某些领域的支票.
if (wsObject.getFoo() == null) return -1;
if (wsObject.getFoo().getBar() == null) return -1;
// maybe also do something with wsObject.getFoo().getBar()
if (wsObject.getFoo().getBar().getBaz() == null) return -1;
return wsObject.getFoo().getBar().getBaz().getInt();
Run Code Online (Sandbox Code Playgroud)
写作是否可以接受
try {
return wsObject.getFoo().getBar().getBaz().getInt();
} catch (NullPointerException ignored) {
return -1;
}
Run Code Online (Sandbox Code Playgroud)
还是会被视为反模式?
java null exception nullpointerexception custom-error-handling
我很惊讶即使StackOverflowError
在Java发生之后仍然可以继续执行.
我知道这StackOverflowError
是类Error的子类.类Error被称为"Throwable的一个子类,表示一个合理的应用程序不应该试图捕获的严重问题".
这听起来更像是一个推荐而不是一个规则,主张捕获像StackOverflowError这样的错误实际上是允许的,这取决于程序员不这样做的合理性.看,我测试了这段代码,它正常终止.
public class Test
{
public static void main(String[] args)
{
try {
foo();
} catch (StackOverflowError e) {
bar();
}
System.out.println("normal termination");
}
private static void foo() {
System.out.println("foo");
foo();
}
private static void bar() {
System.out.println("bar");
}
}
Run Code Online (Sandbox Code Playgroud)
怎么会这样?我想当抛出StackOverflowError时,堆栈应该是如此完整,以至于没有空间调用另一个函数.错误处理块是在不同的堆栈中运行,还是在这里发生了什么?
文档的java.lang.Error
说:
Error是Throwable的子类,表示合理的应用程序不应该尝试捕获的严重问题
但是作为java.lang.Error
子类java.lang.Throwable
,我可以捕获这种类型的Throwable.
我明白为什么抓住这种例外不是一个好主意.据我所知,如果我们决定捕获它,catch处理程序不应该自己分配任何内存.否则OutOfMemoryError
将再次抛出.
所以,我的问题是:
java.lang.OutOfMemoryError
可能是一个好主意?java.lang.OutOfMemoryError
,我们怎么能确定catch处理程序本身不分配任何内存(任何工具或最佳实践)?我已经编程了很长时间,我看到的程序,当它们内存不足时,会尝试清理并退出,即优雅地失败.我不记得上次我看到一个人真正尝试恢复并继续正常运行.
如此多的处理依赖于能够成功分配内存,特别是在垃圾收集语言中,似乎内存不足错误应归类为不可恢复.(不可恢复的错误包括堆栈溢出等.)
使其成为可恢复错误的令人信服的理由是什么?
language-agnostic memory memory-management exception error-recovery
我正在开发一个需要大量内存的程序,我想在发生内存不足异常时捕获.我听说这是不可能做到的,但是如果在这方面有任何发展,我很好奇.
如果有更多对象分配请求进入之前有机会运行GC,JVM是否可以在不重启的情况下从OutOfMemoryError中恢复?
各个JVM实现在这方面有所不同吗?
我的问题是关于JVM恢复而不是用户程序试图通过捕获错误来恢复.换句话说,如果在应用程序服务器(jboss/websphere/..)中抛出OOME,我是否必须重新启动它?或者,如果进一步的请求似乎没有问题,我可以让它运行.
OOME是一类错误,通常你不应该从中恢复.但是如果它被隐藏在一个线程中,或者有人捕获它,那么应用程序可能会进入一个它不会退出的状态,但是没有用处.有关如何防止这种情况的任何建议,即使面对使用可能愚蠢地尝试捕获Throwable或Error/OOME的库?(即您没有直接访问权限来修改源代码)
有时,您只需要捕获Throwable,例如在编写调度程序队列时调度通用项目并需要从任何错误中恢复(所述调度程序记录所有捕获的异常,但是静默,然后继续执行其他项目).
我能想到的一个最佳实践是,如果它是InterruptedException,则总是重新抛出异常,因为这意味着有人打断了我的线程并想要杀死它.
另一个建议(来自评论,而不是答案)是始终重新抛出ThreadDeath
还有其他最佳做法吗?
我们有一个应用程序可以生成新的JVM并代表我们的用户执行代码.有时那些内存耗尽,在这种情况下表现得非常不同.有时它们抛出OutOfMemoryError,有时会冻结.我可以通过一个非常轻量级的后台线程来检测后者,该线程在内存不足时停止发送心跳信号.在那种情况下,我们杀死了JVM,但我们永远无法确定未能获得心跳的真正原因是什么.(它也可能是网络问题或分段错误.)
可靠地检测JVM中内存不足情况的最佳方法是什么?
从理论上讲,-XX:OnOutOfMemoryError选项看起来很有希望,但由于这个错误,它实际上无法使用:https://bugs.openjdk.java.net/browse/JDK-8027434
捕获OutOfMemoryError实际上并不是众所周知的理由(例如,你永远不知道它发生在哪里),尽管它在很多情况下都有效.
剩下的情况是JVM冻结并且不会抛出OutOfMemoryError的情况.我仍然确定记忆是这个问题的原因.
有没有其他选择或解决方法?垃圾收集设置使JVM自行终止而不是冻结?
编辑:我完全控制了分叉和分叉的JVM以及在这些内部执行的代码,两者都在Linux上运行,如果有帮助,可以使用特定于操作系统的实用程序.
我想将Java中的接口方法记录为不允许传播异常,并进行某种形式的静态分析,以验证此方法的实现捕获并处理可能传播给它的任何异常。遵循某种思路@NoThrow
。
例如,我希望能够写:
interface SomeServiceProviderInterface {
@NoThrow
@NonNull
SomeResult someComputation();
}
Run Code Online (Sandbox Code Playgroud)
...并保证实现遵守该接口协定。是否已经有注释和静态分析工具?如果不是,有谁知道这是否可以通过注释处理器来实现(它可以查看代码是否包含try ... catch块吗?)和/或对实现此类操作有任何建议或建议?谢谢!
我注意到,有时候,当内存几乎耗尽时,GC正试图以任何性能价格完成(导致程序几乎冻结,有时多分钟),而不是立即抛出OOME(OutOfMemoryError).
有没有办法在这方面调整GC?
将程序降低到接近零速度使其无响应.在某些情况下,最好是回答"我已经死了",而不是根本没有回应.