Java获取可用内存
有没有什么好方法可以让JVM在运行时获得可用的剩余内存?这种情况的使用案例是,当web服务接近内存限制时,通过拒绝新连接,并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”,而不是因为OutOfMemory错误而突然死亡,从而使web服务正常地失败Java获取可用内存,java,performance,web-services,memory,operating-system,Java,Performance,Web Services,Memory,Operating System,有没有什么好方法可以让JVM在运行时获得可用的剩余内存?这种情况的使用案例是,当web服务接近内存限制时,通过拒绝新连接,并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”,而不是因为OutOfMemory错误而突然死亡,从而使web服务正常地失败 注:这与事先计算/估算每个对象的成本无关。原则上,我可以估计我的对象占用了多少内存,并根据这个估计拒绝新的连接,但这似乎有点粗糙/脆弱。您可以随时调用Runtime.getRuntime().freemory() 问题的另一半,获取对象的成本
注:这与事先计算/估算每个对象的成本无关。原则上,我可以估计我的对象占用了多少内存,并根据这个估计拒绝新的连接,但这似乎有点粗糙/脆弱。您可以随时调用
Runtime.getRuntime().freemory()
问题的另一半,获取对象的成本,对我来说似乎更成问题
我认为更好的解决方案是研究如何对web服务进行集群和扩展,以便它们能够在不拒绝新连接的情况下优雅地接受150%的额定负载。听起来,与代码破解相比,调整大小练习可以为您提供更好的解决方案。Runtime.getRuntime().freemory()
是一种在运行时获得该解决方案的方法。这是好方法还是不好完全取决于您的应用程序。
long freeMemory = Runtime.getRuntime().freeMemory();
编辑:我最初提供了这个示例(链接到William Brendel关于另一个主题的答案)。该主题的创建者(SteveM)希望创建一个多平台Java应用程序。具体来说,用户试图找到一种方法来评估正在运行的机器的资源(磁盘空间、CPU和内存使用)
这是该主题中给出的答案的内联抄本。然而,有人指出,尽管我的回答被标记为已被接受,但这并不是理想的解决方案
public class Main {
public static void main(String[] args) {
/* Total number of processors or cores available to the JVM */
System.out.println("Available processors (cores): " +
Runtime.getRuntime().availableProcessors());
/* Total amount of free memory available to the JVM */
System.out.println("Free memory (bytes): " +
Runtime.getRuntime().freeMemory());
/* This will return Long.MAX_VALUE if there is no preset limit */
long maxMemory = Runtime.getRuntime().maxMemory();
/* Maximum amount of memory the JVM will attempt to use */
System.out.println("Maximum memory (bytes): " +
(maxMemory == Long.MAX_VALUE ? "no limit" : maxMemory));
/* Total memory currently in use by the JVM */
System.out.println("Total memory (bytes): " +
Runtime.getRuntime().totalMemory());
/* Get a list of all filesystem roots on this system */
File[] roots = File.listRoots();
/* For each filesystem root, print some info */
for (File root : roots) {
System.out.println("File system root: " + root.getAbsolutePath());
System.out.println("Total space (bytes): " + root.getTotalSpace());
System.out.println("Free space (bytes): " + root.getFreeSpace());
System.out.println("Usable space (bytes): " + root.getUsableSpace());
}
}
}
用户Christian Fries指出,假设Runtime.getRuntime().freemory()
为您提供了在出现内存不足错误之前可以分配的内存量是错误的
从中,运行时.getRuntime().freeMemory()的签名返回如下:
返回:未来分配对象当前可用内存总量的近似值,以字节为单位
然而,用户Christian Fries声称此功能可能被误解。他声称,在发生内存不足错误之前可能分配的内存量(可用内存)可能由以下公式给出:
long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;
long allocatedMemory =
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
allocatedMemory
由以下人员给出:
long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;
long allocatedMemory =
(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());
这里的关键是自由内存概念之间的差异。一件事是操作系统为Java虚拟机提供的内存。另一个是由Java虚拟机本身实际使用的内存块组成的字节总量
考虑到Java虚拟机以块的形式管理提供给Java应用程序的内存,Java虚拟机可用的可用内存量可能与Java应用程序可用的内存量不完全匹配
long freeMemory = Runtime.getRuntime().freeMemory();
具体来说,Christian Fries表示使用-mx
或-Xmx
标志来设置Java虚拟机可用的最大内存量。他注意到以下功能差异:
/* Returns the maximum amount of memory available to
the Java Virtual Machine set by the '-mx' or '-Xmx' flags. */
Runtime.getRuntime().maxMemory();
/* Returns the total memory allocated from the system
(which can at most reach the maximum memory value
returned by the previous function). */
Runtime.getRuntime().totalMemory();
/* Returns the free memory *within* the total memory
returned by the previous function. */
Runtime.getRuntime().freeMemory();
Christian在总结他的答案时指出,Runtime.getRuntime().freemory()
实际上返回了所谓的可推测的空闲内存;即使将来的内存分配没有超过该函数返回的值,如果Java虚拟机还没有收到主机系统分配的实际内存块,仍然可能会产生一个错误
最后,正确使用的方法将在不同程度上依赖于应用程序的具体情况
long freeMemory = Runtime.getRuntime().freeMemory();
我提供了另一个可能有用的链接。这是一个由用户Richard Dormed提出并由stones333回答的问题。除了另一个答案,我想指出的是,这样做不一定是一个好主意,因为你的应用程序中可能有一个缓存,可以使用
一旦JVM达到内存限制,这样的缓存就会释放内存。即使没有足够的可用内存,分配内存也会首先导致软引用释放内存,并使其可用于分配。除了使用运行时方法外,您还可以使用
MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heap = memBean.getHeapMemoryUsage();
MemoryUsage nonheap = memBean.getNonHeapMemoryUsage();
每个都提供init、used、committed和max值。如果创建一个内存监视器线程来轮询内存并记录它,为您提供一段时间内内存使用的历史记录,这可能会很有用。有时,查看导致错误的内存使用情况会有所帮助
如果你真的想把它发挥到极致,创建一个堆转储线程。随着时间的推移监控内存使用情况,当内存使用情况超过某些阈值时,请执行以下操作(这在JBoss 5.0上有效-您的里程数可能会有所不同):
稍后,您可以使用eclipse或类似工具查看这些堆转储文件,以检查内存泄漏等。注意:到目前为止,所有答案,即使是公认的答案,似乎都是这样回答的:
Runtime.getRuntime().freemory()
提供在发生内存不足错误之前可以分配的内存量。然而,这是错误的
在发生内存不足错误之前可分配的大致内存量,即可能存在可用内存
long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;
在哪里
说明:
如果通过-mx参数(或-Xmx)启动JVM,则指定JVM可用的最大数量Runtime.getRuntime().maxMemory()
将为您提供此金额。JVM将根据这个系统内存量以块的形式分配内存,例如64MB的块。在开始时,JVM将只从系统中分配这样一个块,而不是全部Runtime.getRuntime().totalMemory()
给出从系统分配的总内存,而Runtime.getRuntime().freemory()给出
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
long availableMemory = hal.getMemory().getAvailable();
Runtime runtime = Runtime.getRuntime();
BufferedReader br = new BufferedReader(
new InputStreamReader(runtime.exec("free -m").getInputStream()));
String line;
String memLine = "";
int index = 0;
while ((line = br.readLine()) != null) {
if (index == 1) {
memLine = line;
}
index++;
}
// total used free shared buff/cache available
// Mem: 15933 3153 9683 310 3097 12148
// Swap: 3814 0 3814
List<String> memInfoList = Arrays.asList(memLine.split("\\s+"));
int totalSystemMemory = Integer.parseInt(memInfoList.get(1));
int totalSystemUsedMemory = Integer.parseInt(memInfoList.get(2));
int totalSystemFreeMemory = Integer.parseInt(memInfoList.get(3));
System.out.println("Total system memory in mb: " + totalSystemMemory);
System.out.println("Total system used memory in mb: " + totalSystemUsedMemory);
System.out.println("Total system free memory in mb: " + totalSystemFreeMemory);