【问题标题】:Monitoring java native memory监控java本机内存
【发布时间】:2019-08-12 03:10:53
【问题描述】:

我们正在监控 jvm 指标,如堆、元空间、线程和 gc 计数,我们能够将这些指标推送到监控服务器,如 prometheus。同样,我们想跟踪 Java 本机内存指标(jcmd VM.sumary 的输出)。 我的问题是,是否可以通过调用任何 jvm 运行时类来获取这些指标?

【问题讨论】:

  • 监控VM.sumary并不是真的有用,因为NMT可能经常报告less内存比实际使用情况,也可能报告more而不是进程的真实RSS。我建议改为监视RSS
  • 在 Linux 上,监视来自的 RSS 非常容易 - 只需解析 /proc/[pid]/stat 输出。要从应用程序中监控 JVM 本机内存使用情况,请解析 /proc/self/stat
  • 感谢@apangin 的链接。我的整个想法是减少进程内存,但我想监控本机内存使用情况,以便我们了解大部分内存的去向。
  • @UdayShankar,如果您要解析 /proc/... 文件,也可以查看 /proc/</pid>/maps。但正如 Shipilev 所说 (shipilev.net/jvm/anatomy-quarks/12-native-memory-tracking):“这 [使用 JVM 的 NMT] 比试图通过解析来自例如 /proc/$pid/maps 的不透明内存映射来弄清楚 JVM 在做什么要容易得多”

标签: java jvm monitoring prometheus jcmd


【解决方案1】:

是的,可以直接从 Java 应用程序获取 NativeMemoryTracking 摘要:

import javax.management.JMException;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;

public class DiagnosticCommand {

    public static String execute(String command, String... args) throws JMException {
        return (String) ManagementFactory.getPlatformMBeanServer().invoke(
                new ObjectName("com.sun.management:type=DiagnosticCommand"),
                command,
                new Object[]{args},
                new String[]{"[Ljava.lang.String;"});
    }

    public static void main(String[] args) throws Exception {
        String summary = DiagnosticCommand.execute("vmNativeMemory", "summary");
        System.out.println(summary);
    }
}

不过,您必须解析文本输出。

请注意,NMT 报告中最重要的部分可以使用指定的 MBean 单独跟踪,包括

  • Java 堆
  • 代码缓存
  • 元空间
  • 压缩类空间
  • 直接字节缓冲区和映射字节缓冲区

请参阅 MemoryPoolMXBeanBufferPoolMXBean

正如我在 cmets 中所说,监控 NMT 输出在实践中并不总是有帮助,因为它不能直接反映进程使用的实际物理内存。 NMT 可以报告much less 内存比实际使用量,或者它也可以从操作系统的角度报告more 内存比进程消耗的内存。

由于 NMT 可能会错过 Java 进程消耗的大量操作系统内存,因此监视进程的驻留集大小 (RSS) 也很有用。在 Linux 上,这可以通过解析 /proc/[pid]/stat/proc/[pid]/status 来完成。

【讨论】:

    【解决方案2】:

    我认为没有 Java API。 您最好的选择可能是调用jcmd <PID> VM.native_memory 命令并解析其输出。 当然,您需要先为您的进程启用本机内存跟踪。

    【讨论】:

    • There is 一个 Java API。虽然它仍然需要解析文本输出。
    【解决方案3】:

    您可以在JMX 中找到许多您想要的东西。问题“为什么使用 JMX 技术?”的答案之一是“监视和管理 Java VM”。在Oracle doc:

    Java 虚拟机 (Java VM) 使用 JMX 技术进行了高度检测。您可以启动 JMX 代理来访问内置的 Java VM 工具,从而远程监控和管理 Java VM。

    //Metaspace
    for (MemoryPoolMXBean memoryMXBean : ManagementFactory.getMemoryPoolMXBeans()) {
        if ("Metaspace".equals(memoryMXBean.getName())) {
                System.out.println(memoryMXBean.getUsage().getUsed());
                System.out.println(memoryMXBean.getUsage().getCommitted());
                System.out.println(memoryMXBean.getUsage().getMax());
                System.out.println(memoryMXBean.getUsage().getInit());
        }
    }
    
    //current number of live threads including both daemon and non-daemon threads
    int threadCount = ManagementFactory.getThreadMXBean().getThreadCount();
    
    //Returns the current memory usage of the heap and non-heap
    MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
    MemoryUsage heapMemory = memoryMXBean.getHeapMemoryUsage();
    MemoryUsage nonHeapMemory = memoryMXBean.getNonHeapMemoryUsage();
    
    //GarbageCollector total number of collections
    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
    long totalCollectionCount = garbageCollectorMXBeans.stream().mapToLong(x -> x.getCollectionCount()).sum();
    

    【讨论】:

    • 感谢您的回答,但我更感兴趣的是了解其他 jvm 内存部分(如代码、GC、编译器、内部、符号和未知部分)随着处理时间的增加而增加
    【解决方案4】:

    尽管您没有提到Micrometer,但我想指出我为获取诸如驻留集大小(RSS) 之类的procfs 信息而编写的一个小支持库。 也许您可以从中提取一些有用的代码。实际上,procfs 代码与 Micrometer 无关(尽管不被视为公共 API)。这里是:https://github.com/mweirauch/micrometer-jvm-extras

    【讨论】:

    • 感谢 @mweirauch 的 github 项目,我可以用它来获取进程的整体内存。我也有兴趣确切了解其他 jvm 内存部分,如代码、GC、编译器、内部、符号和未知部分是如何随着处理时间而增加的。
    猜你喜欢
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多