Java获得可用内存

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (11)

有没有什么好的方法可以在运行时为JVM提供剩余内存?这种情况的用例应该是让Web服务在接近内存限制时正常地失败,拒绝新的连接,出现一个错误消息“太多人使用它,稍后再试”,而不是突然死于OutOfMemory错误。

请注意,这与事先计算/估计每个对象的成本无关。原则上,我可以根据估计估计出我的对象占用了多少内存并拒绝新的连接,但这看起来有点拙劣/脆弱。

提问于
用户回答回答于

William Brendel的这个例子可能有些用处。

我最初提供这个样本(链接到威廉Brendel在另一个话题上的答案)。该主题的创建者(Steve M)想要创建一个多平台的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().freeMemory()给出了可以分配的内存量直到发生内存不足错误为止是错误的。

文档中,签名返回Runtime.getRuntime().freeMemory()是这样的:

返回:近似可用于未来分配对象的总内存量,以字节为单位。

但是,用户Christian Fries称这个功能可能会被误解。他声称,发生内存不足错误(可用内存)之前可以分配的大致内存量可能由下式给出:

long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;

由于allocatedMemory

long allocatedMemory = 
  (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory());

这里的关键是自由记忆概念之间的差异。一件事是操作系统提供Java虚拟机的内存。另一个是由Java虚拟机本身实际使用的内存块组成的字节总量。

考虑到给予Java应用程序的内存由Java虚拟机以块的形式管理,Java虚拟机可用的可用内存量可能与Java应用程序可用的内存量不完全匹配。

具体来说,Christian Fries表示使用-mxor -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();

基督徒总结他的回答,说Runtime.getRuntime().freeMemory()实际上它返回了可以被称为自由记忆的东西; 即使未来的内存分配未超过该函数返回的值,如果Java虚拟机尚未收到主机系统分配的实际内存块,java.lang.OutOfMemoryError仍可能会产生a。

最后,正确的使用方法将对应用程序的具体情况有不同程度的依赖。

用户回答回答于

到目前为止所有的答案,即使是接受的答案,似乎都回答了这个问题,它说明了Runtime.getRuntime().freeMemory()给出的内存量可以分配到内存不足错误发生之前。但是:这是错误的。

在内存不足错误发生之前可以分配的大致内存量,即可能的内存量

long presumableFreeMemory = Runtime.getRuntime().maxMemory() - allocatedMemory;

哪里

long allocatedMemory      = (Runtime.getRuntime().totalMemory()-Runtime.getRuntime().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对于空闲内存来说是一个很好的指示器。

扫码关注云+社区