有没有什么好的方法可以让JVM在运行时获得剩余的可用内存?这种方法的用例是当Web服务接近其内存限制时,通过拒绝新的连接并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”来使Web服务优雅地失败,而不是因为OutOfMemory错误而突然死亡。
注意,这与预先计算/估计每个对象的成本无关。原则上,我可以估计我的对象占用多少内存,并根据估计拒绝新的连接,但这似乎有点笨拙/脆弱。
有没有什么好的方法可以让JVM在运行时获得剩余的可用内存?这种方法的用例是当Web服务接近其内存限制时,通过拒绝新的连接并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”来使Web服务优雅地失败,而不是因为OutOfMemory错误而突然死亡。
注意,这与预先计算/估计每个对象的成本无关。原则上,我可以估计我的对象占用多少内存,并根据估计拒绝新的连接,但这似乎有点笨拙/脆弱。
9条答案
按热度按时间kqlmhetl1#
This sample by William Brendel may be of some use.
编辑:我最初提供了这个示例(链接到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提出的问题,由stones 333 about determining the default Java heap size used.回答
gg58donl2#
注意:到目前为止,所有的答案,即使是公认的答案,似乎都是通过
Runtime.getRuntime().freeMemory()
给出了内存不足错误发生之前可以分配的内存量来回答这个问题的。但是:这是不对。在发生内存不足错误之前可以分配的 * 近似 * 内存量,即空闲内存可能
其中
Runtime.getRuntime().maxMemory()
将为您提供此内存量。JVM将根据此系统内存量以块为单位分配内存,例如64 MB的块。开始时,JVM将仅从系统中分配此类块,而不是全部内存量。Runtime.getRuntime().totalMemory()
提供从系统中分配的总内存量,而Runtime.getRuntime().freeMemory()
提供分配的总内存量 * 内 * 的可用内存量。因此:
是JVM已经保留的空闲内存,但可能只是一小部分。您可能会得到
presumableFreeMemory
。当然,即使您尝试分配的内存量小于presumableFreeMemory
,您也可能会得到内存不足异常。如果JVM没有从系统中获得下一个内存块,就可能发生这种情况。但是,在大多数系统上,这种情况永远不会发生,系统将开始交换-您希望避免的情况。如果将-mx设置为合理的值,则presumableFreeMemory
是空闲内存的良好指示符。pkbketx93#
要获取操作系统范围内的可用内存,请使用以下maven依赖项添加
OSHI
:然后在Java中使用以下代码:
u7up0aaq4#
除了使用Runtime方法之外,您还可以使用
每个MemoryUsage都提供init、used、committed和max值。如果创建一个内存监控线程来轮询内存并记录它,这可能会很有用,它会为您提供一段时间内的内存使用历史。有时,查看导致错误的一段时间内的内存使用情况会很有帮助。
如果你真的想把它发挥到极致,创建一个堆转储线程,监视你的内存使用情况,当它超过一定的阈值时,执行以下操作(这在JBoss 5.0上有效-你的里程可能会有所不同):
稍后,您可以使用eclipse memory analyzer或类似的工具检查这些堆转储文件,以检查内存泄漏等。
mwg9r5ms5#
除了另一个答案,我想指出的是,这样做不一定是一个好主意,因为你可能有一个缓存在您的应用程序使用SoftReferences。
这种缓存会在JVM达到内存限制时立即释放内存。分配内存时,即使没有足够的可用内存,也会首先导致软引用释放内存,使其可用于分配。
dba5bblo6#
您可以随时调用
Runtime.getRuntime().freeMemory()
。问题的另一半,获得对象的成本,对我来说似乎更成问题。
我认为一个更好的解决方案应该是弄清楚如何集群和扩展你的Web服务,这样它们就可以优雅地接受150%的额定负载而不拒绝新的连接。听起来规模调整练习会比代码黑客给你一个更好的解决方案。
rlcwz9us7#
要获取物理机总、已用和可用内存信息,我们还可以使用带有命令参数
free -m
的javaRuntime.exec()
,然后将其解释为如下所示:nbysray58#
nukf8bse9#
Runtime.getRuntime().freeMemory()
是一种在运行时获取free memory for JVM的方法。这是一种好的方法(或)不完全取决于你的应用程序。