从 Java 跟踪本机内存使用情况?

Track native memory usage from Java?

有什么方法可以从 Java 记录本机内存使用情况,即直接本机内存或进程使用的总内存(例如,询问 OS)?

我想 运行 在幕后的用户机器上执行此操作,因此 NativeMemoryTracking 命令行工具并不是最吸引人的选择。我已经记录了 free/max/total 堆大小。

背景:我的软件的用户报告了一个异常(如下),我不知道为什么。我的程序确实使用了 SWIG 的本机代码,但它是一个简单的 API,我认为它没有内存泄漏,并且不在堆栈跟踪中(或 运行 紧接在错误之前) .我的日志显示错误发生时有大量堆 space 可用。所以我真的不知道如何追踪它。

java.lang.OutOfMemoryError: null
    at java.io.RandomAccessFile.writeBytes0(Native Method) ~[na:1.7.0_45]
    at java.io.RandomAccessFile.writeBytes(Unknown Source) ~[na:1.7.0_45]
    at java.io.RandomAccessFile.write(Unknown Source) ~[na:1.7.0_45]

错误发生在 Windows(7 或 10)(?) 从 webstart 中,配置了这些参数:

<java href="http://java.sun.com/products/autodl/j2se" initial-heap-size="768m" java-vm-args="" max-heap-size="900m" version="1.7+"/>

这里有一段代码,将字符串设置为已用内存量 (mb)/总内存量 (mb),然后您可以根据需要使用它来记录!

Runtime instance = Runtime.getRuntime();
String mem = "Memory Used: "+ (instance.totalMemory() - instance.freeMemory()) / mb +"MB ("+
   (int)((instance.totalMemory() - instance.freeMemory())*1.0/instance.totalMemory()*100.0)+"%)"

如果你想在你的特定方法或代码行上跟踪 JVM 内存,你可以使用运行时 API。

    Runtime runtime = Runtime.getRuntime();
    NumberFormat format = NumberFormat.getInstance();

    long maxMemory = runtime.maxMemory();
    long allocatedMemory = runtime.totalMemory();
    long freeMemory = runtime.freeMemory();

System.out.println("free memory: " + format.format(freeMemory / 1024));
System.out.println("allocated memory: " + format.format(allocatedMemory / 1024));
System.out.println("max memory: " + format.format(maxMemory / 1024));
System.out.println("total free memory: " + format.format((freeMemory + (maxMemory - allocatedMemory)) / 1024));
public final void writeBytes(String s) throws IOException {
    int len = s.length();
    byte[] b = new byte[len];
    s.getBytes(0, len, b, 0);
    writeBytes(b, 0, len);
}

查看源代码,足够大的字符串可能会导致内存不足错误。我怀疑您的堆日志是在此之前完成的,这解释了您看到的空闲堆 space。我建议您验证是否是这种情况,如果是,请限制字符串大小 and/or 增加堆大小。

我最终使用了 this 代码,它向 OS 询问 RSS 和峰值内存使用情况。因为我已经设置了 SWIG 模块,所以我可以直接添加。代码可能不是线程安全的,因为我在测试时遇到了一个随机的 malloc 异常,这意味着我不确定是否要将它保留在那里。

我真的很惊讶 JVM 没有提供执行此操作的方法。如果有办法请告诉我。