https://segmentfault.com/a/1190000044509636
 

  是挺久没有“宠爱”我们netty小婊贝了,最近又开始搞事了。

于是,趁机探究了下MXBean关于direct memory的监控原理。

一、问题

  通过arthas dashboard中的direct,visualvm的MBeans以及jmx获取的grafana监控都无法看到直接内存有大量占用,但实际上应用已经在OOM的边缘。

······

那难道拿这个“小可爱”没法了吗?只能祭出终极绝招:添加jvm启动参数-XX:NativeMemoryTracking=detail

简单说一下NMT,NMT(本地内存跟踪)是JDK自带的功能,方法简单,可以用它跟踪JVM内存使用情况。使用方法:

1. 启用NMT(启动加参数):-XX:NativeMemoryTracking=detail
2. 简单的执行命令:jcmd $pid VM.native_memory detail

即可打印:Java Heap、Class、Thread、Code、GC、Compiler、Internal、Symbol、Native Memory Tracking、Arena Chunk 内存可用、已占用情况。

其中:Java Heap即-Xmx的设置和占用情况;
Thread包含线程数量和线程本身占用内存(-Xss乘以线程数量)的情况;
Internal包含直接内存(Direct Memory,受-XX:MaxDirectMemorySize限制)

二、MXBean监控直接内存案例

  一般我们可以使用MXBean通过下面的方式获取直接内存的使用情况:

private static final Logger LOG = LoggerFactory.getLogger(MemoryStatics.class);
// direct memory
public static BufferPoolMXBean directMBean;
// mapped memory
public static BufferPoolMXBean mappedMXBean; static {
List<BufferPoolMXBean> bufferPoolMXBeans = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class); for (BufferPoolMXBean mbean : bufferPoolMXBeans) {
if (mbean.getName().equals("direct")) {
directMBean= mbean;
} else {
mappedMXBean = mbean;
}
}
}
public void monitor() { while (true) {
assert directMBean != null;
LOG.info("buffer pool name: " + directMBean);
LOG.info("memory used: " + directMBean.getMemoryUsed());
LOG.info("max memory : " + directMBean.getTotalCapacity());
LOG.info("contain buffers : " + directMBean.getCount());
LOG.info("---------------------------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

arthas的mbean命令和visualvm的MBeans中的BufferPool原理上也是类似的。

三、BufferPoolMXBean底层原理

  上面的案例中,通过getMemoryUsed、getTotalCapacity、getCount方法获取实际direct memory的使用情况。而真正的实现类是JDK的sun.management.ManagementFactoryHelper(JDK8) 【可以直接打印mbean对象,可以看见类似对象信息:sun.management.ManagementFactoryHelper$1@de2b39c】:

而上面这段代码可以看到有getName、getCount、getTotalCapacity等方法,其真正实现都是在java.nio.Bits中,实现如下:

Bits类中有几个静态成员,简单说明:

// 最大直接内存,默认和-Xmx配置的大小一样
private static volatile long maxMemory = VM.maxDirectMemory();
// 已使用的直接内存大小
private static final AtomicLong reservedMemory = new AtomicLong();
// 总的直接内存大小,小于等于maxMemory
private static final AtomicLong totalCapacity = new AtomicLong();

在使用java.nio.ByteBuffer.allocateDirect或者DirectByteBuffer主构造函数时,每次分配直接内存都会调用Bits类进行实际分配并更新reservedMemorytotalCapacity等值。

关于DirectByteBuffer可以看之前的一篇《从HotSpot源码理解DirectByteBuffer》

DirectByteBuffer主构造函数如下:

netty的直接内存分配

  简单说明下netty的直接内存分配。netty直接内存分配最终是通过PlatformDependent实现的,这个类有个原子类的静态成员DIRECT_MEMORY_COUNTER独立进行内存使用记录,不依赖Bits.

// PlatformDependent直接内存记录器
private static final AtomicLong DIRECT_MEMORY_COUNTER;

每次要申请一块新的direct memory的时候, 它就调用incrementMemoryCounter方法去增加 DIRECT_MEMORY_COUNTER 的值:

最终是通过反射实例化DirectByteBuffer,用的是下面的构造函数:

PlatformDependent0反射实例化代码:

因此netty所分配的直接内存大小,常规的监控手段无法监测,包括arthas、visualvm中的MBean、以及其他所有通过jmx获取直接内存数据的手段。

如果要监控,只能自定义实现,从PlatformDependent入手,网上已有不少资料。

[转帖]直接内存监控不准确,netty玩了什么花?的更多相关文章

  1. 一文了解 Redis 内存监控和内存消耗

    Redis 是一种内存数据库,将数据保存在内存中,读写效率要比传统的将数据保存在磁盘上的数据库要快很多.所以,监控 Redis 的内存消耗并了解 Redis 内存模型对高效并长期稳定使用 Redis ...

  2. 用python 10min手写一个简易的实时内存监控系统

    简易的内存监控系统 本文需要有一定的python和前端基础,如果没基础的,请关注我后续的基础教程系列博客 文章github源地址,还可以看到具体的代码,喜欢请在原链接右上角加个star 腾讯视频链接 ...

  3. Docker容器内存监控

    linux内存监控 要明白docker容器内存是如何计算的,首先要明白linux中内存的相关概念. 使用free命令可以查看当前内存使用情况. [root@localhost ~]$ free tot ...

  4. iOS微信内存监控

    WeTest 导读 目前iOS主流的内存监控工具是Instruments的Allocations,但只能用于开发阶段.本文介绍如何实现离线化的内存监控工具,用于App上线后发现内存问题. FOOM(F ...

  5. [转]用python 10min手写一个简易的实时内存监控系统

    简易的内存监控系统 本文需要有一定的python和前端基础,如果没基础的,请关注我后续的基础教程系列博客 文章github源地址,还可以看到具体的代码,喜欢请在原链接右上角加个star 腾讯视频链接 ...

  6. docker内存监控与压测

    一直运行的docker容器显示内存已经耗尽,并且容器内存耗尽也没出现重启情况,通过后台查看发现进程没有占用多少内存.内存的监控使用的是cadvisor,计算方式也是使用cadvisor的页面计算方式, ...

  7. 从Container内存监控限制到CPU使用率限制方案

    转自:http://blog.csdn.net/Androidlushangderen/article/details/50282593 前言 最近在运维我们部门的hadoop集群时,发现了很多Job ...

  8. redis内存监控与回收

    Redis有自己的内存分配器,当key-value对象被移除时,Redis不会马上向操作系统释放其占用内存.redis之所以这样的设计有两个原因. OS可能会将释放内存交换到虚拟内存,但OS的虚拟内存 ...

  9. 10min 手写一个内存监控系统

    本文的目的在于,尽可能用简单的代码,让大家了解内存监控的原理,及思想.更容易去理解Nagios.Zabbix.Ganglia监控原理,文章最后还有视频教程链接哦,从零敲出来的全过程 思路分为下面几块: ...

  10. 【性能测试】:JVM内存监控策略的方法,以及监控结果说明

    JVM内存监控主要在稳定性压测期间,监控应用服务器内存泄露等问题: [JVM远程监控设置] 1.打开WAS控制台:https://ip:port/ibm/console/login.do 2.进入路径 ...

随机推荐

  1. Python——第一章:注释、变量、常量

    python中的注释有2种: 1.单行注释 单行注释用# #这是一个单行注释 快捷键用Ctrl+/全选多个内容可以多行快速注释,也可以快速去掉注释符# 比如快速将全选的所有行注释掉--加# 2.多行注 ...

  2. linux文件摘选

    显示/var目录下所有以1开头,以一个小写字母结尾,且中间至少出现一位数字(可以由其他字符)的文件或目录. 命令: ls -d /var/1*[0-9]*[a-z] [root@foundation0 ...

  3. [ACTF2020 新生赛]Exec 1

    [ACTF2020 新生赛]Exec 1 审题 发现题目有ping功能,猜测是命令执行漏洞. 知识点 linux系统命令 解题 先ping127.0.0.1,观察是否正常执行. 发现正常后执行ls / ...

  4. 11、层叠布局(Stack、Align、 Positioned)

    Flutter Stack组件 Stack表示堆的意思,我们可以用Stack或者Stack结合Align或者Stack结合 Positiond来实现页面的定位 布局  Alignment(对齐)类是用 ...

  5. 六一儿童节,看我用ModelArts让8090梦回童年

    [本期推荐] 8岁小朋友的儿童节,有点硬核,一起来认识这些小小程序员,看他们如何coding出一个与众不同的童年. 摘要: 如果还能再过一次儿童节-- 本文分享自华为云社区<"梦回童年 ...

  6. 直播实时数仓基于DataLeap开放平台在发布管控场景的业务实践

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 背景 业务背景 随着字节业务的高速增长,业务场景越来越丰富,业务基于数据做的决策也越来越多,对数据的时效性要求也越 ...

  7. 火山引擎DataLeap数据质量动态探查及相关前端实现

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 需求背景 火山引擎DataLeap数据探查上线之前,数据验证都是通过写SQL方式进行查询的,从编写SQL,到解析运 ...

  8. 火山引擎 DataTester:一个 A/B 测试,将一款游戏的核心收益提升了 8%

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 随着社会节奏及生活方式的改变,休闲游戏在移动游戏市场的占比逐渐升高,据伽马数据发布的<2022 年休闲游戏发 ...

  9. OpenShift 与 OpenStack:让云变得更简单

    OpenShift 与 OpenStack 都是在 2010.2011 年左右创建的,用于构建可扩展云平台的开源技术,两者都用于在混合云环境中构建可扩展系统.从历史来看,OpenStack 的存在时间 ...

  10. IDEA 2021.2 新建JavaWeb项目及Tomcat部署

    前文:JSP 简单入门与 IDEA 开发环境配置 参考链接: https://zhuanlan.zhihu.com/p/68133583 https://www.cnblogs.com/javabg/ ...