首页 > 解决方案 > Runtime.freeMemory() 和公司或提前分配,以防止后期内存不足错误

问题描述

我正在编写一个程序,根据JVM、堆大小和用户设置,它可能会经常抛出一些OOM错误。

我不想给它一些任意的限制,但是因为当这个错误发生时,程序可能需要很长时间才能产生一些有意义的输出,我希望它至少尽快退出如果OOM要发生。我的第一种方法是尽早初始化最消耗内存的对象,这可能不是一个好习惯。

由于稍后可能需要更多内存,具体取决于用户输入,我还想确保一些合理安全的可用内存余量,并且在一些糟糕的想法之后,我发现使用方法 fromRuntime并为用户提供一些关于剩余内存的数据,关于可以从该数据中得到什么并在需要时发出警告将是一个更优雅的解决方案。

早期初始化的对象之一是用于写入音频文件的数组,直到程序结束才使用它,我考虑将其大小添加到可用内存计算中,并仅在需要时对其进行初始化。

据我所知,之前计算可用内存的主要缺陷如下:

  1. 它并不完全准确
  2. 对于某些对象,堆内存中的实际大小无法预测,取决于实现
  3. 在极端情况下,程序仍然会在计算结束时终止,当对象被初始化时,不会在没有足够的内存来完成程序时立即终止。重复检查可能是一种解决方案,但这会影响性能。

早期初始化的主要问题如下:

  1. 它冻结了一些未使用的资源,可能会影响性能。

  2. 可能会影响代码的可读性和可维护性,尤其是在误用和/或在较大的程序中时。

  3. 导致程序总是以错误退出,而不是阻止它并以优雅的方式退出。

在大多数情况下,解决此类问题的最佳方法是什么,是否有更好的解决方案或其他应考虑的因素,或者我提到的某些因素或多或少比我认为的重要?

PS我可能可以并且应该改进内存管理,这在大多数情况下可以缓解或几乎解决问题,关心内存管理应该是优先事项,但我认为这仍然是一个有效的问题。我知道 Runtime.freeMemory() 不能像乍一看那样使用。

编辑

我将尝试澄清我所说的早期 OOM 的含义。

内存块 A(从一开始就使用,可以通过选项合理预测)

内存块 B(可变,取决于用户输入)

内存块 C(最后使用,可以通过选项合理预测)

正常方式:A,B,长时间计算,C(这里可能会发生OOM)

早期初始化:A ,C ,B (这里很可能会发生 OOM),长时间计算

我错过了一个重要的点(并且在大多数现实世界的程序中可能超过其他点)是 A 和 B 的一些内存可能会在使用 C 之前被释放,并且即使不需要它,早期初始化也会导致程序失败.

标签: javaout-of-memory

解决方案


如果您想根据应用程序内存不足的时间做不同的事情,您可以使用Thread.setDefaultUncaughtExceptionHandler(...). 预关闭逻辑可能需要一些内存,您需要预先分配并在需要时释放。

byte[] memory = new byte[4096];
final AtomicBoolean shuttingDown = new AtomicBoolean();

Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
    if (throwable instanceof OutOfMemoryError) {
        if (shuttingDown.getAndSet(true)) return; // Execute the following logic only once
        memory = null; // Release pre-allocated memory
        // Do pre-shutdown logic
        System.exit(0);
    }
});

推荐阅读