Java获取可用内存

新手上路,请多包涵

有没有什么好的方法可以让JVM在运行时可以使用剩余的内存?这个用例是让 web 服务在接近内存限制时优雅地失败,方法是拒绝新连接并显示一条很好的错误消息“太多人使用这个,稍后再试”,而不是突然死于 OutOfMemory 错误.

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

原文由 Li Haoyi 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 866
2 个回答

William Brendel 的这个样本可能会有一些用处。

编辑:我最初提供了这个示例(链接到 William 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 表示使用 -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().freeMemory() 实际上返回了所谓的假定空闲内存;即使未来的内存分配不超过该函数返回的值,如果 Java 虚拟机尚未收到主机系统分配的实际内存块,仍可能会生成 java.lang.OutOfMemoryError

最后,正确的使用方法将在不同程度上取决于您的应用程序的细节。

我提供了另一个可能有用的链接。这是一个由用户 Richard Dormand 提出并由 stones333 回答的 关于确定使用的默认 Java 堆大小的问题。

原文由 Blitzkoder 发布,翻译遵循 CC BY-SA 3.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 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题