Java获取可用内存

Java获取可用内存,java,performance,web-services,memory,operating-system,Java,Performance,Web Services,Memory,Operating System,有没有什么好方法可以让JVM在运行时获得可用的剩余内存?这种情况的使用案例是,当web服务接近内存限制时,通过拒绝新连接,并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”,而不是因为OutOfMemory错误而突然死亡,从而使web服务正常地失败 注:这与事先计算/估算每个对象的成本无关。原则上,我可以估计我的对象占用了多少内存,并根据这个估计拒绝新的连接,但这似乎有点粗糙/脆弱。您可以随时调用Runtime.getRuntime().freemory() 问题的另一半,获取对象的成本

有没有什么好方法可以让JVM在运行时获得可用的剩余内存?这种情况的使用案例是,当web服务接近内存限制时,通过拒绝新连接,并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”,而不是因为OutOfMemory错误而突然死亡,从而使web服务正常地失败


注:这与事先计算/估算每个对象的成本无关。原则上,我可以估计我的对象占用了多少内存,并根据这个估计拒绝新的连接,但这似乎有点粗糙/脆弱。

您可以随时调用
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);