Java 线上服务查看 Direct 及 Mapped 堆外内存

Java JVM About 7,958 words

需求

需要查看线上服务占用堆外内存的情况。

困难

jcmd等命令行工具,无法查看堆外内存的情况。

NMT也没有追踪堆外内存。

Kubernetes中部署,无法再映射JMX端口提供给jconsole使用。

解决方法一

在代码中提前使用MXBean,定时轮训获取。

List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
for (BufferPoolMXBean bufferPoolMXBean : bufferPoolMXBeans) {
    System.out.println(bufferPoolMXBean.getObjectName().toString() + ", " + bufferPoolMXBean.getName() + ", " + bufferPoolMXBean.getCount() + ", " + bufferPoolMXBean.getMemoryUsed() + ", " + bufferPoolMXBean.getTotalCapacity());
}

输出

java.nio:type=BufferPool,name=mapped, mapped, 0, 0, 0
java.nio:type=BufferPool,name=direct, direct, 1, 16383, 16383

解决方法二

查看 JMX 状态

jcmd 1 ManagementAgent.status

禁用状态时输出

bash-4.4$ jcmd 1 ManagementAgent.status
1:
Agent: disabled

JMX已启动时输出

❯ jcmd 1 ManagementAgent.status
1:
Agent: enabled

Connection Type: local
Protocol       : rmi
Host           : 127.0.0.1
URL            : service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc2AAtVbmljYXN0UmVmMgAACzEwLjg4Ljk0Ljg0AADgM29dCMHwZ+DOU7Ho2AAAAYlD4VYkgAEAeA==
Properties     :
  com.sun.management.jmxremote.ssl = true [default]
  com.sun.management.config.file = management.properties [default]
  com.sun.management.jmxremote.local.only = true [default]
  com.sun.management.jmxremote.access.file = jmxremote.access [default]
  com.sun.management.jmxremote.port = 0 [default]
  com.sun.management.jmxremote.registry.ssl = false [default]
  com.sun.management.jmxremote.authenticate = true [default]
  com.sun.management.jmxremote.ssl.need.client.auth = false [default]
  com.sun.management.jmxremote.password.file = jmxremote.password [default]

开启本地 JMX

jcmd 1 ManagementAgent.start_local

输出

❯ jcmd 1 ManagementAgent.start_local
1:
Command executed successfully

jshell

使用jshell打开Java自动的脚本执行引擎。

/exit命令退出jshell

❯ jshell
|  欢迎使用 JShell -- 版本 11.0.17
|  要大致了解该版本, 请键入: /help intro

jshell> /exit
|  再见

脚本代码

import javax.management.*;
import javax.management.remote.*;
import javax.management.openmbean.*;

String serviceUrl = "service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc2AAtVbmljYXN0UmVmMgAACzEwLjg4Ljk0Ljg0AADgM29dCMHwZ+DOU7Ho2AAAAYlD4VYkgAEAeA==";
JMXServiceURL url = new JMXServiceURL(serviceUrl);
try (JMXConnector connect = JMXConnectorFactory.connect(url)) {
    MBeanServerConnection connection = connect.getMBeanServerConnection();
    ObjectName memoryObjectName = ObjectName.getInstance("java.lang:type=Memory");
    CompositeDataSupport heapMemoryUsage = (CompositeDataSupport) connection.getAttribute(memoryObjectName, "HeapMemoryUsage");
    CompositeDataSupport nonHeapMemoryUsage = (CompositeDataSupport) connection.getAttribute(memoryObjectName, "NonHeapMemoryUsage");
    System.out.println("heap committed: " + heapMemoryUsage.get("committed"));
    System.out.println("heap init: " + heapMemoryUsage.get("init"));
    System.out.println("heap max: " + heapMemoryUsage.get("max"));
    System.out.println("heap used: " + heapMemoryUsage.get("used"));
    System.out.println("non-heap committed: " + nonHeapMemoryUsage.get("committed"));
    System.out.println("non-heap init: " + nonHeapMemoryUsage.get("init"));
    System.out.println("non-heap max: " + nonHeapMemoryUsage.get("max"));
    System.out.println("non-heap used: " + nonHeapMemoryUsage.get("used"));

    ObjectName mappedObjectName = ObjectName.getInstance("java.nio:name=mapped,type=BufferPool");
    Object mappedTotalCapacity = connection.getAttribute(mappedObjectName, "TotalCapacity");
    Object mappedMemoryUsed = connection.getAttribute(mappedObjectName, "MemoryUsed");
    System.out.println("buffer pool mapped total capacity: " + mappedTotalCapacity);
    System.out.println("buffer pool mapped memory used: " + mappedMemoryUsed);

    ObjectName directObjectName = ObjectName.getInstance("java.nio:name=direct,type=BufferPool");
    Object directTotalCapacity = connection.getAttribute(directObjectName, "TotalCapacity");
    Object directMemoryUsed = connection.getAttribute(directObjectName, "MemoryUsed");
    System.out.println("buffer pool direct total capacity: " + directTotalCapacity);
    System.out.println("buffer pool direct memory used: " + directMemoryUsed);
}

输出

❯ jshell
|  欢迎使用 JShell -- 版本 11.0.17
|  要大致了解该版本, 请键入: /help intro

jshell> import javax.management.*;
   ...> import javax.management.remote.*;
   ...> import javax.management.openmbean.*;
   ...>
   ...> String serviceUrl = "service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZheC5tYW5hZ2VtZW50LnJlbW90ZS5ybWkuUk1JU2VydmVySW1wbF9TdHViAAAAAAAAAAICAAB4cgAaamF2YS5ybWkuc2VydmVyLlJlbW90ZVN0dWLp/tzJi+FlGgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc2AAtVbmljYXN0UmVmMgAACzEwLjg4Ljk0Ljg0AADgM29dCMHwZ+DOU7Ho2AAAAYlD4VYkgAEAeA==";
   ...> JMXServiceURL url = new JMXServiceURL(serviceUrl);
   ...> try (JMXConnector connect = JMXConnectorFactory.connect(url)) {
   ...>     MBeanServerConnection connection = connect.getMBeanServerConnection();
   ...>     ObjectName memoryObjectName = ObjectName.getInstance("java.lang:type=Memory");
   ...>     CompositeDataSupport heapMemoryUsage = (CompositeDataSupport) connection.getAttribute(memoryObjectName, "HeapMemoryUsage");
   ...>     CompositeDataSupport nonHeapMemoryUsage = (CompositeDataSupport) connection.getAttribute(memoryObjectName, "NonHeapMemoryUsage");
   ...>     System.out.println("heap committed: " + heapMemoryUsage.get("committed"));
   ...>     System.out.println("heap init: " + heapMemoryUsage.get("init"));
   ...>     System.out.println("heap max: " + heapMemoryUsage.get("max"));
   ...>     System.out.println("heap used: " + heapMemoryUsage.get("used"));
   ...>     System.out.println("non-heap committed: " + nonHeapMemoryUsage.get("committed"));
   ...>     System.out.println("non-heap init: " + nonHeapMemoryUsage.get("init"));
   ...>     System.out.println("non-heap max: " + nonHeapMemoryUsage.get("max"));
   ...>     System.out.println("non-heap used: " + nonHeapMemoryUsage.get("used"));
   ...>
   ...>     ObjectName mappedObjectName = ObjectName.getInstance("java.nio:name=mapped,type=BufferPool");
   ...>     Object mappedTotalCapacity = connection.getAttribute(mappedObjectName, "TotalCapacity");
   ...>     Object mappedMemoryUsed = connection.getAttribute(mappedObjectName, "MemoryUsed");
   ...>     System.out.println("buffer pool mapped total capacity: " + mappedTotalCapacity);
   ...>     System.out.println("buffer pool mapped memory used: " + mappedMemoryUsed);
   ...>
   ...>     ObjectName directObjectName = ObjectName.getInstance("java.nio:name=direct,type=BufferPool");
   ...>     Object directTotalCapacity = connection.getAttribute(directObjectName, "TotalCapacity");
   ...>     Object directMemoryUsed = connection.getAttribute(directObjectName, "MemoryUsed");
   ...>     System.out.println("buffer pool direct total capacity: " + directTotalCapacity);
   ...>     System.out.println("buffer pool direct memory used: " + directMemoryUsed);
   ...> }
serviceUrl ==> "service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZ ... OU7Ho2AAAAYlD4VYkgAEAeA=="
url ==> service:jmx:rmi://127.0.0.1/stub/rO0ABXNyAC5qYXZh ... DOU7Ho2AAAAYlD4VYkgAEAeA==
heap committed: 536870912
heap init: 536870912
heap max: 8589934592
heap used: 245366784
non-heap committed: 35586048
non-heap init: 7667712
non-heap max: -1
non-heap used: 32305288
buffer pool mapped total capacity: 0
buffer pool mapped memory used: 0
buffer pool direct total capacity: 16383
buffer pool direct memory used: 16383

jshell> /exit
|  再见
Views: 830 · Posted: 2023-12-21

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓


Today On History
Browsing Refresh