有没有什么好的方法可以让JVM在运行时可以使用剩余的内存?这个用例是让 web 服务在接近内存限制时优雅地失败,方法是拒绝新连接并显示一条很好的错误消息“太多人使用这个,稍后再试”,而不是突然死于 OutOfMemory 错误.
请注意,这与事先计算/估算每个对象的成本无关。原则上我可以估计我的对象占用多少内存并根据该估计拒绝新连接,但这似乎有点不可靠/脆弱。
原文由 Li Haoyi 发布,翻译遵循 CC BY-SA 4.0 许可协议
有没有什么好的方法可以让JVM在运行时可以使用剩余的内存?这个用例是让 web 服务在接近内存限制时优雅地失败,方法是拒绝新连接并显示一条很好的错误消息“太多人使用这个,稍后再试”,而不是突然死于 OutOfMemory 错误.
请注意,这与事先计算/估算每个对象的成本无关。原则上我可以估计我的对象占用多少内存并根据该估计拒绝新连接,但这似乎有点不可靠/脆弱。
原文由 Li Haoyi 发布,翻译遵循 CC BY-SA 4.0 许可协议
注意:到目前为止,所有答案,甚至是已接受的答案,似乎都通过说 Runtime.getRuntime().freeMemory()
为您提供了在发生内存不足错误之前可能分配的内存量来回答问题。然而:这是错误的。
在发生内存不足错误之前可能分配的 大致 内存量,即可能有空闲内存
Runtime runtime = Runtime.getRuntime();
long presumableFreeMemory = runtime.maxMemory() - allocatedMemory;
在哪里
long allocatedMemory = runtime.totalMemory() - runtime.freeMemory();
说明: 如果您通过 -mx 参数(或 -Xmx)启动 JVM,您指定了 JVM 可用的最大数量。 Runtime.getRuntime().maxMemory()
会给你这个数额。 JVM 将从这个系统内存量中分配内存块,例如 64 MB 的块。开始时,JVM 只会从系统中分配这样的块,而不是全部。 Runtime.getRuntime().totalMemory()
给出从系统分配的总内存,而 Runtime.getRuntime().freeMemory()
给出分配的总内存 中 的空闲内存。
因此:
long definitelyFreeMemory = Runtime.getRuntime().freeMemory();
是 JVM 已经保留的空闲内存,但可能只是一小部分。你可能会得到 presumableFreeMemory
。当然,即使您尝试分配小于 presumableFreeMemory
的数量,您也可能会遇到内存不足的异常。如果 JVM 没有从系统中获取下一个内存块,则可能会发生这种情况。然而,在大多数系统上,这永远不会发生,系统宁愿开始交换——这是您希望避免的情况。对于最初的问题:如果 -mx 设置为合理的值,那么 presumableFreeMemory
是可用内存的良好指标。
原文由 Christian Fries 发布,翻译遵循 CC BY-SA 4.0 许可协议
15 回答8.4k 阅读
8 回答6.2k 阅读
1 回答4k 阅读✓ 已解决
3 回答2.2k 阅读✓ 已解决
2 回答3.1k 阅读
2 回答3.8k 阅读
3 回答1.7k 阅读✓ 已解决
William Brendel 的这个样本可能会有一些用处。
编辑:我最初提供了这个示例(链接到 William Brendel 在另一个主题上的回答)。该主题的创建者 (Steve M) 想要创建一个多平台 Java 应用程序。具体来说,用户试图找到一种方法来评估正在运行的机器的资源(磁盘空间、CPU 和内存使用情况)。
这是该主题中给出的答案的内联抄本。然而,尽管我的回答被标记为已接受,但有人指出,这不是理想的解决方案。
用户 Christian Fries 指出,假设
Runtime.getRuntime().freeMemory()
为您提供在发生内存不足错误之前可能分配的内存量是错误的。从 文档 中,
Runtime.getRuntime().freeMemory()
的签名返回是这样的:返回: 当前可用于未来分配对象的内存总量的近似值,以字节为单位。
然而,用户 Christian Fries 声称此功能可能会被误解。他声称在发生内存不足错误(可用内存)之前可能分配的大概内存量可能由以下公式给出:
allocatedMemory
由以下人员给出:这里的关键是空闲内存概念之间的差异。一件事是操作系统为 Java 虚拟机提供的内存。另一个是 Java 虚拟机本身实际使用的内存块的总字节数。
考虑到提供给 Java 应用程序的内存是由 Java 虚拟机按块管理的,因此 Java 虚拟机可用的 空闲内存 量可能与 Java 应用程序可用的内存量不完全匹配。
具体来说,Christian Fries 表示使用
-mx
或-Xmx
标志来设置 Java 虚拟机可用的最大内存量。他注意到以下功能差异:Christian 总结他的回答时说
Runtime.getRuntime().freeMemory()
实际上返回了所谓的假定空闲内存;即使未来的内存分配不超过该函数返回的值,如果 Java 虚拟机尚未收到主机系统分配的实际内存块,仍可能会生成java.lang.OutOfMemoryError
。最后,正确的使用方法将在不同程度上取决于您的应用程序的细节。
我提供了另一个可能有用的链接。这是一个由用户 Richard Dormand 提出并由 stones333 回答的 关于确定使用的默认 Java 堆大小的问题。