Web Services Java获取可用内存

hc2pp10m  于 2022-11-15  发布在  Java
关注(0)|答案(9)|浏览(162)

有没有什么好的方法可以让JVM在运行时获得剩余的可用内存?这种方法的用例是当Web服务接近其内存限制时,通过拒绝新的连接并显示一条漂亮的错误消息“太多人在使用此服务,请稍后重试”来使Web服务优雅地失败,而不是因为OutOfMemory错误而突然死亡。
注意,这与预先计算/估计每个对象的成本无关。原则上,我可以估计我的对象占用多少内存,并根据估计拒绝新的连接,但这似乎有点笨拙/脆弱。

kqlmhetl

kqlmhetl1#

This sample by William Brendel may be of some use.
编辑:我最初提供了这个示例(链接到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提出的问题,由stones 333 about determining the default Java heap size used.回答

gg58donl

gg58donl2#

注意:到目前为止,所有的答案,即使是公认的答案,似乎都是通过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是空闲内存的良好指示符。

pkbketx9

pkbketx93#

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

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

u7up0aaq4#

除了使用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 memory analyzer或类似的工具检查这些堆转储文件,以检查内存泄漏等。

mwg9r5ms

mwg9r5ms5#

除了另一个答案,我想指出的是,这样做不一定是一个好主意,因为你可能有一个缓存在您的应用程序使用SoftReferences
这种缓存会在JVM达到内存限制时立即释放内存。分配内存时,即使没有足够的可用内存,也会首先导致软引用释放内存,使其可用于分配。

dba5bblo

dba5bblo6#

您可以随时调用Runtime.getRuntime().freeMemory()
问题的另一半,获得对象的成本,对我来说似乎更成问题。
我认为一个更好的解决方案应该是弄清楚如何集群和扩展你的Web服务,这样它们就可以优雅地接受150%的额定负载而不拒绝新的连接。听起来规模调整练习会比代码黑客给你一个更好的解决方案。

rlcwz9us

rlcwz9us7#

要获取物理机已用可用内存信息,我们还可以使用带有命令参数free -m的java Runtime.exec(),然后将其解释为如下所示:

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

nbysray58#

long freeMemory = Runtime.getRuntime().freeMemory();
nukf8bse

nukf8bse9#

Runtime.getRuntime().freeMemory()是一种在运行时获取free memory for JVM的方法。这是一种好的方法(或)不完全取决于你的应用程序。

相关问题