代码之家  ›  专栏  ›  技术社区  ›  rellocs wood

如何侦听OutOfMemoryError并退出JVM[复制]

  •  11
  • rellocs wood  · 技术社区  · 8 年前

    有没有办法建立一个全球 OutOfMemoryError 我的Java应用程序的侦听器?

    我想优雅地停止JVM( try-catch 不是OOM上的选项)。

    3 回复  |  直到 8 年前
        1
  •  16
  •   Jigar Joshi    8 年前

    您可以使用 JVM option

    -XX:OnOutOfMemoryError="<cmd args>; <cmd args>"
    

    并执行您选择的命令

        2
  •  7
  •   Boann    8 年前

    OutOfMemoryError 通常不会被捕获,最简单的方法之一是

    Thread.setDefaultUncaughtExceptionHandler((thread,t) -> {
        if(t instanceof OutOfMemoryError) {
            System.exit(1);
        }
    });
    

    但在某些情况下,例如通过 ExecutorService ,将自动捕获所有丢弃的对象。不过,在这些情况下,应用程序中应该有一些代码来评估结果并处理异常情况。

    但也许你想做出反应 之前 太晚了,例如,在内存不足之前保存挂起的数据。解决方案将朝以下方向发展:

    MemoryMXBean mBean = ManagementFactory.getMemoryMXBean();
    ((NotificationEmitter)mBean).addNotificationListener(
        (n, mb) -> {
            MemoryUsage mu = ((MemoryMXBean)mb).getHeapMemoryUsage();
            if(mu.getUsed()*100/mu.getMax() > 80)
                System.out.println("more than 80% used");// may initiate a shut down
        },
        n -> n.getType().equals(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED),
        mBean);
    
    for(MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
        if(pool.getType() == MemoryType.HEAP && pool.isCollectionUsageThresholdSupported()) {
            pool.setCollectionUsageThreshold((int)Math.floor(pool.getUsage().getMax()*0.8));
        }
    }
    

    不幸的是,当堆的总使用率超过阈值时,无法简单地接收通知,因此,我们必须在支持它的每个内存池上安装一个阈值(通常是终身生成),并在通知时重新检查总使用率,以便在总使用率超过阈值时触发关机。

        3
  •  5
  •   prunge    8 年前

    还有 ExitOnOutOfMemoryError option 用作JVM命令行选项。

    -XX:OnOutOfMemoryError
    

    ExitOnOutOfMemoryError—启用此选项时,JVM将在第一次出现内存不足错误时退出。如果您希望重新启动JVM实例而不是处理内存不足错误,可以使用它。

    这不是真正的 优雅的 JVM退出,我认为关闭挂钩不会运行。