我们正在监控JVM指标,如堆、元空间、线程和垃圾回收计数,并能将这些指标推送到监控服务器,如prometheus。同样地,我们想要跟踪Java本机内存指标(jcmd VM.sumary的输出)。我的问题是,是否可以通过调用任何JVM运行时类来获取这些指标?
是的,可以直接从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报告的最重要部分可以使用指定的MBeans单独跟踪,包括
请参见MemoryPoolMXBean和BufferPoolMXBean。
正如我在评论中所说,监视NMT输出在实践中并不总是有用的,因为它不能直接反映进程实际使用的物理内存。 NMT可能会报告比实际使用量少的内存,或者它也可能会报告从操作系统角度来看进程消耗的内存更多。
由于NMT可能会忽略Java进程消耗的大量操作系统内存,因此监视进程的常驻集大小(RSS)也是很有用的。在Linux上,可以通过解析/proc/[pid]/stat
或/proc/[pid]/status
来完成此操作。
我认为没有Java API可以做到这一点。
你最好的选择可能是调用jcmd <PID> VM.native_memory
命令并解析其输出。
当然,你需要先为进程启用本地内存跟踪。
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();
虽然您没有提到Micrometer
,但我想指出一个小型支持库,我编写了一个获取procfs信息(如Resident Set Size(RSS))的方法。也许您可以从中提取一些有用的代码。实际上,procfs代码与Micrometer无关(尽管不被视为公共API)。这是它的链接:https://github.com/mweirauch/micrometer-jvm-extras
VM.summary
并不是很有用,因为NMT经常会报告比实际使用更少的内存,同时也可能会报告比进程的真实RSS更多的内存。我建议监控RSS而不是VM.summary。 - apangin/proc/[pid]/stat
输出即可。为了从应用程序内部监视JVM本机内存使用情况,请解析/proc/self/stat
。 - apangin/proc/<pid>/maps
。 但正如Shipilev所说(https://shipilev.net/jvm/anatomy-quarks/12-native-memory-tracking/):“使用JVM的NMT比尝试通过解析例如/proc/$pid/maps中的不透明内存映射来弄清楚JVM正在做什么要容易得多,多得多。” - Juraj Martinka