基于Fault Tolerance的方法避免java.lang.OutOfMemoryError

时间:2012-09-27 22:07:12

标签: java memory-management out-of-memory fault-tolerance

java.lang.OutOfMemoryError已经浪费了许多精心设计的Java代码。似乎没有任何缓解,甚至生产类代码也被它击落。

我想问的问题是:是否有良好的编程/架构实践,您可以避免遇到此错误。

因此,Java程序员处理的工具似乎是:

  1. java.lang.Runtime.addShutdownHook(Thread hook) - 关闭钩子允许优雅的摔倒。
  2. java.lang.Runtime.freeMemory() - 允许我们检查VM可用的内存
  3. 所以我的想法是:可以在创建对象之前编写工厂方法,在尝试分配内存之前检查系统是否有足够的内存吗?例如在C语言中,malloc会失败并且你会知道你的内存耗尽,这不是一个理想的情况,但你不会从java.lang.OutOfMemoryError动作中消失。

    建议的方法是更好的内存管理或插入内存泄漏或只是分配更多内存 - 我同意这些是有价值的观点,但让我们看看以下场景:

    1. 我在亚马逊微型实例上运行
    2. 我可以为我的VM分配很少的内存,比如400M
    3. 我的Java进程以多线程方式处理作业,每个线程根据计算任务的参数消耗可变数量的内存
    4. 假设我的进程没有内存泄漏
    5. 现在,如果我在完成工作之前继续为它们提供工作,那么最终将死于记忆饥饿
    6. 如果我将-Xmx设置得太高 - 我会在操作系统上进行交换和可能的颠簸
    7. 如果我设置了一个较高的并发限制 - 这可能不是最佳的,因为我可以限制接受可以使用可用RAM执行的作业,或者更糟糕的是接受需要大量内存并最终命中的作业无论如何,java.lang.OutOfMemoryError。 X.希望这有助于解释问题的动机 - 我认为标准响应与寻求容错方法解决问题并不相互排斥。
    8. 提前致谢。

2 个答案:

答案 0 :(得分:2)

我们更多地将JVM内存作为调整参数处理,而不是像应用程序那样主动管理。我们有一个MemoryInfo类(它包含了几个Runtime内存信息方法)。

在应用程序运行时,我们会在应用程序中跟踪可用内存:

 Runtime.getMaxMemory() - Runtime.getTotalMemory() + Runtime.getFreeMemory();

最大内存是-Xmx jvm arg,总内存是JVM已经分配给应用程序堆的内存,可用内存是分配的堆内存仍然可用的数量。 (如果您的-Xms参数与-Xmx参数相同,那么您需要检查getFreeMemory()。)

如果我们的内存使用量超过70%,我们会向监控系统发送警报。在那时,我们决定是否可以在当天的剩余时间里跛行,或者是否调整-Xmx参数并重新启动。虽然这看起来有点混乱,但实际上,一旦我们调整了系统,我们永远不会在此之后遇到内存问题。 (一旦你使用了超过90%的最大内存,JVM将非常频繁地尝试GC以防止内存不足。)

我认为在每种结构中管理内存的方法都很简单,但如果你需要绝对控制,那么也许它是有道理的。另一种方法是确保您使用的任何内存缓存都具有LRU或Expiration and reload机制,这样您就可以更好地限制内存中保留的对象数。

那就是说,我们的方法是尽可能地保留在内存中,并且只需分配足够的RAM。我们的大系统分配了28G RAM(我们平均使用40-60%)。

答案 1 :(得分:1)

好的,正如我之前所建议的那样,解决方案是需要更少的内存。运行无限量的线程没有意义,因为您的进程会收到多个请求。限制每个进程中的线程数,并且最多同时处理该数量的请求。其余的请求只会等待。

由于你没有无限数量的核心,无论如何,太多线程都是个坏主意。