基于容错的避免java.lang.OutOfMemoryError的方法

基于容错的避免java.lang.OutOfMemoryError的方法,java,memory-management,out-of-memory,fault-tolerance,Java,Memory Management,Out Of Memory,Fault Tolerance,Java.lang.OutOfMemoryError浪费了许多精心编制的Java代码。它似乎并没有缓解任何压力,甚至生产类代码也会因此而崩溃 我想问的问题是:是否有好的编程/架构实践可以避免出现这种错误 因此,Java程序员使用的工具似乎是: java.lang.Runtime.addShutdownHook(线程挂钩)——关闭挂钩允许优雅的下降 java.lang.Runtime.freeMemory()--允许我们检查VM可用的内存 所以我的想法是:在创建对象之前,是否可以编写工厂方法,在尝

Java.lang.OutOfMemoryError浪费了许多精心编制的Java代码。它似乎并没有缓解任何压力,甚至生产类代码也会因此而崩溃

我想问的问题是:是否有好的编程/架构实践可以避免出现这种错误

因此,Java程序员使用的工具似乎是:

  • java.lang.Runtime.addShutdownHook(线程挂钩)——关闭挂钩允许优雅的下降
  • java.lang.Runtime.freeMemory()--允许我们检查VM可用的内存
  • 所以我的想法是:在创建对象之前,是否可以编写工厂方法,在尝试分配内存之前检查系统是否有足够的内存?例如,在C中,malloc会失败,您会知道内存已经用完,这不是一个理想的情况,但您不会因为java.lang.OutOfMemoryError动脉瘤而死亡

    一种建议的方法是更好地管理内存,或者堵塞内存泄漏,或者简单地分配更多内存——我同意这些都是有价值的观点,但让我们看看以下场景:

  • 我正在运行一个Amazon微实例
  • 我可以为我的虚拟机分配很少的内存,比如说400万
  • 我的Java进程以多线程方式处理作业,每个线程根据计算任务的参数消耗可变的内存量
  • 让我们假设我的进程没有内存泄漏
  • 现在,如果我在它们完成之前继续给它喂食,它最终会死于内存不足
  • 如果我将-Xmx设置得太高,那么我将在操作系统上进行交换,甚至可能会出现颠簸
  • 如果我同时设置一个上限——这可能不是最优的,因为我可能会限制接受一个可以使用可用RAM执行的作业,或者更糟糕的是,接受一个需要大量内存的作业,最终还是会遇到java.lang.OutOfMemoryError。 X.希望这有助于解释问题的动机——我认为标准答案对于寻求解决问题的容错方法并不是相互排斥的
    提前谢谢

    我们处理JVM内存更多的是作为一个调优参数,而不是作为应用程序主动管理的东西。我们有一个MemoryInfo类(它封装了几个运行时内存信息方法)

    当应用程序运行时,我们跟踪应用程序中的可用内存,如下所示:

     Runtime.getMaxMemory() - Runtime.getTotalMemory() + Runtime.getFreeMemory();
    
    Max memory是-Xmx jvm参数,total memory是jvm已经分配给应用程序堆的内存,free memory是分配的堆内存中仍有多少可用。(如果-Xms参数与-Xmx参数相同,则只需检查
    getFreeMemory()

    如果我们的内存使用率超过70%,我们会向监控系统发送警报。在这一点上,我们决定是否可以在一天剩下的时间里蹒跚而行,或者是否调整-Xmx参数并重新启动。虽然这看起来有点混乱,但在实践中,一旦我们调整了一个系统,我们就再也不会遇到内存问题了。(一旦使用的最大内存超过90%,JVM将非常频繁地进行GC,以防止内存耗尽)

    我认为用每一种构造管理内存的方法都是严格的,但是如果你需要绝对控制,那么它可能是有意义的。另一种方法是确保您使用的任何内存缓存都具有LRU或过期和重新加载机制,这样您就可以更好地限制内存中保留的对象数量


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

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


    因为您没有无限数量的内核,所以过多的线程是个坏主意。

    切换到64位JVM并安装一次又一次的内存加载?内存不足是因为分配太多(故意或由于泄漏)。首先找出你是否在泄漏,如果没有,试着提高效率。或者切换到64位JVM,加载内存。您好@zmbq,感谢您的回复,我将根据您的回复添加注释。即使有办法知道您是否即将耗尽内存,您的应用程序的逻辑将如何处理它?问题就如@zmbq所说:你的应用程序需要大量的内存,在这种情况下,你要么需要使它不使用太多的内存,要么放入更多的内存,要么使用64位;或者您正在泄漏内存,在这种情况下,您应该修复代码——即使有更多的RAM,最终也会耗尽。我不认为这是一个很好的问题,但如果你真的使用了大量RAM,你可以解释它的用途,也许我们可以提供减少使用的建议。在每次创建对象时不断执行剩余内存检查的性能权衡是什么?我似乎更倾向于在设计阶段、负载测试以及对可能导致错误的数据有效负载实施限制期间减少对错误的暴露。但这是一个永恒的伟大主题。期待阅读更多的回复。嗨@gregmac,如果你看看我更新的问题——我希望这能解释这个场景。因此,例如,如果我受RAM限制,我可以在分配新对象之前轮询可用RAM,如果可用RAM小于某个设置参数,则执行延迟自旋锁或拒绝请求。这样做的目的是让对象消耗掉系统中暂时存在的RAM,它们最终会被释放,但就在这一秒,我不想分配更多的对象