如果JVM有机会在更多对象分配请求出现之前运行GC,那么JVM是否可以从OutOfMemoryError中恢复而无需重新启动?
各种JVM实现在这方面是否有所不同?
我的问题是关于JVM恢复,而不是用户程序试图通过捕获错误进行恢复。换句话说,如果将OOME抛出到应用程序服务器(jboss / websphere / ..)中,我是否必须重新启动它?或者,如果其他请求似乎没有问题,我可以让它运行。
它可能有效,但是通常是一个坏主意。无法保证你的应用程序将成功恢复,或者无法知道它是否成功。例如:
即使采取恢复步骤(例如释放保留的内存块)后,实际上可能没有足够的内存来执行请求的任务。在这种情况下,你的应用程序可能会陷入循环,在该循环中,它似乎反复出现恢复,然后再次耗尽内存。
OOME可以在任何线程上抛出。如果应用程序线程或库未设计为应对该问题,则可能会使某些长期存在的数据结构处于不完整或不一致的状态。
如果线程由于OOME而死,则作为OOME恢复的一部分,应用程序可能需要重新启动线程。至少,这会使应用程序更加复杂。
假设一个线程使用通知/等待或某种更高级别的机制与其他线程同步。如果该线程从OOME中退出,则可能会留下其他线程来等待通知(etc),这些消息永远不会出现…例如。为此进行设计可能会使应用程序更加复杂。
总而言之,设计,实施和测试要从OOME中恢复的应用程序可能会很困难,尤其是在应用程序(或其运行所在的框架或所使用的任何库)是多线程的情况下。将OOME视为致命错误是一个更好的主意。
另请参阅我对相关问题的回答:
编辑 -针对此后续问题:
换句话说,如果将OOME抛出到应用程序服务器(jboss / websphere / ..)中,我是否必须重新启动它?
不,你不必须重新启动。但这可能是明智的,特别是如果你没有良好/自动的方法来检查服务是否正常运行时。
JVM将恢复正常。但是,应用程序服务器和应用程序本身可能会恢复,也可能无法恢复,这取决于它们为应对这种情况而设计的程度。(我的经验是,某些应用程序服务器并非旨在解决此问题,并且设计和实施复杂的应用程序以从OOME中恢复非常困难,而正确测试它甚至更加困难。)
编辑2
针对此评论:
“其他线程可能会等待通知(等)永远不会到来”真的吗?被杀死的线程是否不会解开其堆栈,随即释放资源,包括持有的锁?
对真的!考虑一下:
线程#1运行此命令:
synchronized(lock) {
while (!someCondition) {
lock.wait();
}
}
// ...
线程#2运行此命令:
synchronized(lock) {
// do stuff
lock.notify();
}
如果线程#1正在等待通知,并且线程#2在该// do something
部分中获得OOME ,则线程#2将不会进行notify()
调用,线程#1可能会永远卡住,等待永远不会发生的通知。当然,可以保证线程#2
释放lock
对象上的互斥体…但这还不够!
如果不是,则线程运行的代码不是异常安全的,这是一个更普遍的问题。
我听说过“异常安全”这个词(尽管我知道你的意思)。Java程序通常不设计为可应对意外异常。确实,在上述情况下,使应用程序异常安全很可能介于困难与不可能之间。
你需要某种机制将线程#1的故障(由于OOME)变成对线程#2的线程间通信失败通知。Erlang可以做到这一点……但是Java却没有。他们之所以能够在Erlang中执行此操作,是因为Erlang进程使用严格的类似CSP的原语进行通信。即没有共享的数据结构!
(请注意,几乎所有意外的异常都可能导致上述问题……而不仅仅是Error异常。在某些类型的Java代码中,尝试从意外的异常中恢复可能会严重失败。)
希望有人能帮我找出,如果不是一个解决方案,至少是一个行为的解释。 问题: 在一些设备上,按下启动器图标会导致当前任务恢复,在其他设备上,会导致初始启动意图被激发(有效地重新启动应用程序)。为什么会这样? 细节: 当您按下“启动程序图标”时,应用程序会正常启动-也就是说,我假设,使用您的第一个和操作和类别。然而,情况并非总是如此: 在大多数设备上,如果您在应用程序已经运行后按下启动器图标,则会恢复该
问题内容: 我正在尝试为我的Java游戏添加重启/重播功能。当前在我的Game类(GUI和游戏被初始化的地方)中,我有: 游戏对象包含整个游戏窗口的GUI,并包含各种对象(例如实际游戏窗口,计分板,倒数计时器等)。 我想添加一个功能,如果他们单击GUI上的重新启动按钮或游戏结束后,游戏将重新启动(以及倒计时和计分)。我确实意识到最好重新实例化对象(计分,倒数),但是一旦实例化,它们便成为我的GUI
问题内容: 例如,我可以同时在Ubuntu 14.04上安装Atlas,OpenBlas,MKL并在它们之间切换而无需重新编译Caffe吗? 问题答案: 当然,您必须安装它们,并在Ubuntu / Debian上发出命令 您将获得编号列表的替代品,并可以在它们之间轻松切换 链接:https://wiki.debian.org/DebianScience/LinearAlgebraLibraries
问题内容: 我想使用Redis从命令行,脚本,Web和电子表格中查询数据。除了电子表格,我可以找到所有其他示例的好例子……不过,我不太清楚从何处开始从MS Excel电子表格进行访问。谷歌让我失望。 请让我知道您会如何建议这样做,谢谢! 那些陌生的Redis的ps是此处描述的键值数据存储区:http : //code.google.com/p/redis/ 问题答案: 我想我用XLLoop找到了我
问题内容: 如果我的进程正在加载.so库,并且该库有新版本可用,是否可以在不重新启动进程的情况下切换到新库?还是答案取决于诸如库中现有功能之一是否有参数更改之类的事情? 我正在一个相当大的系统中工作,该系统运行100多个进程,每个系统加载10多个库。这些库提供特定的功能,并由独立的团队提供。因此,当其中一个库发生更改(可以说是针对错误修复)时,理想的做法是在后台发布它而不影响运行的过程。可能吗 ?
问题内容: 如果我在Thread对象上使用start()并且run()方法返回,是否可以再次调用start()? 例如, 我只是想知道是因为我的代码抛出了IllegalThreadStateExceptions,所以想知道是否是因为您不能执行上述操作。 问题答案: 不,你不能。该方法的Javadoc 告诉您!