当前位置: 首页 > 面试题库 >

JVM是否可以从OutOfMemoryError中恢复而无需重新启动

桑坚
2023-03-14
问题内容
  1. 如果JVM有机会在更多对象分配请求出现之前运行GC,那么JVM是否可以从OutOfMemoryError中恢复而无需重新启动?

  2. 各种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 告诉您!