【发布时间】:2020-06-02 23:39:03
【问题描述】:
我正在编写一个程序,根据 JVM、堆大小和用户设置,它可能会经常抛出一些 OOM 错误。
我不想给它一些任意的限制,但是因为当这个错误发生时,程序可能需要很长时间才能产生一些有意义的输出,我希望它至少退出如果OOM 即将发生,请尽快。我的第一种方法是尽早初始化最消耗内存的对象,这可能不是一个好习惯。
由于以后可能需要更多内存,具体取决于用户输入,我还想确保一些合理安全的可用内存余量,经过一些糟糕的想法后,我发现使用 Runtime 中的方法并给用户一些关于剩余内存的数据,关于可以从该数据中得到什么的数据,并在需要时发出警告将是一个更优雅的解决方案。
早期初始化的对象之一是用于写入音频文件的数组,直到程序结束才使用它,我考虑将其大小添加到空闲内存计算中,并仅在需要时对其进行初始化。
据我所知,之前计算空闲内存的主要缺陷如下:
- 并不完全准确
- 对于某些对象,堆内存中的实际大小无法预测,具体取决于实现
- 在极端情况下,程序仍将在计算结束时终止,当对象初始化时,不会在没有足够的内存完成程序时立即终止。重复检查可能是一种解决方案,但这会影响性能。
早期初始化的主要问题如下:
-
它会冻结一些未使用的资源,可能会影响性能。
-
可能会影响代码的可读性和可维护性,尤其是在误用和/或在大型程序中时。
-
导致程序总是以错误退出而不是阻止它并以优雅的方式退出。
在大多数情况下,解决此类问题的最佳方法是什么,是否有更好的解决方案或其他应考虑的因素,或者我提到的某些因素比我认为的重要或重要?
PS 我可能可以并且应该改进内存管理,这将在大多数情况下缓解或几乎解决问题,关心内存管理应该是优先事项,但我认为这仍然是一个有效的问题。我知道 Runtime.freeMemory() 不能像乍一看那样使用。
编辑
我将尝试澄清早期 OOM 的含义。
内存块 A(从一开始就使用,可以通过选项合理预测)
内存块 B(可变,取决于用户输入)
内存块 C(最后使用,可通过选项合理预测)
正常方式:A ,B ,长时间计算,C (这里很可能会发生OOM)
早期初始化:A ,C ,B (这里很可能会发生OOM),长时间计算
我错过了一个重要的点(并且在大多数现实世界的程序中可能超过其他点)是 A 和 B 的一些内存可能会在使用 C 之前被释放,早期初始化会导致程序失败,即使没有需要它。
【问题讨论】:
-
我不确定我是否遵循。 没有某种所需的内存预计算,应用程序应该如何知道 OOM 会发生?
-
在另一种情况下,应用程序不知道 OOM 会发生,OOM 只是发生得更早,因为对象,至少是可预测的对象,是在使用之前很久就创建的。也欢迎对其他类型的内存预计算提出建议。
-
“我不想给它一些任意限制”:你为什么要给任意限制?您应该知道您的程序需要多少内存 + 保留一些回旋余地以解决不同 JVM 之间的差异。尝试预测 OOME 何时发生是危险的,应该避免。
-
如果尝试预测 OOME 何时发生是危险的并且没有理由给它一些任意限制,我应该如何知道我的程序需要多少内存?
标签: java out-of-memory