Java获得可用内存

java performance web-services memory operating-system

68363 观看

8回复

5670 作者的声誉

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

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

作者: Li Haoyi 的来源 发布者: 2012 年 10 月 9 日

回应 8


0

275610 作者的声誉

你总是可以打电话Runtime.getRuntime().freeMemory()

问题的另一半,即获得对象的成本,对我来说似乎更成问题。

我认为更好的解决方案是找出如何集群和扩展您的Web服务,以便他们可以优雅地接受150%的额定负载,而不会拒绝新的连接。听起来像一个大小调整练习会让你得到一个比代​​码破解更好的解决方案。

作者: duffymo 发布者: 2012 年 10 月 9 日

0

59717 作者的声誉

Runtime.getRuntime().freeMemory()是一种在运行时获取JVM空闲内存的方法。是好方法(或)不完全取决于您的应用程序。

作者: kosa 发布者: 2012 年 10 月 9 日

0

301 作者的声誉

long freeMemory = Runtime.getRuntime().freeMemory();
作者: Ryan Anderson 发布者: 2012 年 10 月 9 日

74

1101 作者的声誉

决定

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();

克里斯蒂安总结了他的答案,说明Runtime.getRuntime().freeMemory()事实上可以回归所谓的可能的自由记忆; 即使未来的内存分配没有超过该函数返回的值,如果Java虚拟机尚未收到主机系统分配的实际内存块,java.lang.OutOfMemoryError仍可能产生a。

最后,正确使用的方法将对应用程序的细节有不同程度的依赖性。

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

作者: Blitzkoder 发布者: 2012 年 10 月 9 日

5

560614 作者的声誉

除了另一个答案之外,我想要注意的是,这样做不一定是个好主意,因为您的应用程序中可能有一个使用SoftReferences的缓存。

一旦JVM达到其内存限制,这样的缓存就会释放内存。分配内存,即使没有足够的可用内存,也会首先导致内存被软引用释放,并使其可用于分配。

作者: JB Nizet 发布者: 2012 年 10 月 9 日

7

6982 作者的声誉

除了使用Runtime方法之外,您还可以使用获取一些额外的内存信息

MemoryMXBean memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heap = memBean.getHeapMemoryUsage();
MemoryUsage nonheap = memBean.getNonHeapMemoryUsage();

每个MemoryUsage提供init,used,committed和max值。如果创建一个内存监视器线程来轮询内存并将其记录下来,这可能很有用,为您提供一段时间内存使用情况的历史记录。有时,查看导致错误的内存使用情况会很有帮助。

如果你真的想把它变为极端,那就创建一个堆转储线程。监控你的内存使用情况随着时间的推移,当它超过一定的阈值时,执行以下操作(这适用于JBoss 5.0 - 你的里程可能会有所不同):

// init code
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean diagBean = ManagementFactory.newPlatformMXBeanProxy(server, "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class); 

// loop code
// add some code to figure if we have passed some threshold, then

File heapFile = new File(outputDir, "heap-" + curThreshold + ".hprof");
log.info("Dumping heap file " + heapFile.getAbsolutePath());
diagBean.dumpHeap(heapFile.getAbsolutePath(), true);

稍后您可以使用eclipse 内存分析器或类似工具查看这些堆转储文件,以检查内存泄漏等。

作者: Guido Simone 发布者: 2012 年 10 月 9 日

61

9852 作者的声誉

注意:到目前为止所有答案,即使是已接受的答案,似乎都回答了这个问题,它说明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没有从系统获取下一个内存块,则可能会发生这种情况。但是,在大多数系统上,这种情况永远不会发生,系统宁愿开始交换 - 这是您想要避免的情况。Wrt原来的问题:如果-mx设置为合理的值,那么它presumableFreeMemory是空闲内存的一个很好的指标。

作者: Christian Fries 发布者: 2013 年 8 月 21 日

5

1373 作者的声誉

要获取操作系统范围内的可用内存,请OSHI使用以下maven依赖项添加:

<dependency>
    <groupId>com.github.oshi</groupId>
    <artifactId>oshi-core</artifactId>
    <version>LATEST</version>
</dependency>

然后在Java中,使用以下代码:

SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hal = si.getHardware();
long availableMemory = hal.getMemory().getAvailable();
作者: Oleksii Kyslytsyn 发布者: 2016 年 4 月 10 日
32x32