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. ElasticSearch之cat pending tasks API

    命令样例如下: curl -X GET "https://localhost:9200/_cat/pending_tasks?v=true&pretty" --cacert ...

  2. 聊聊ChatGLM6B的微调脚本及与Huggingface的关联

    本文首先分析微调脚本trainer.sh的内容,再剖析ChatGLM是如何与Huggingface平台对接,实现transformers库的API直接调用ChatGLM模型,最后定位到了ChatGLM ...

  3. Json Schema介绍 和 .net 下的实践 - 基于Lateapexearlyspeed.Json.Schema - 基础1 - type关键字和string类型

    本系列旨在介绍Json Schema的常见用法,以及.net实现库Lateapexearlyspeed.Json.Schema的使用 这篇文章将介绍Json Schema中的type关键字,和stri ...

  4. Cesium案例解析(九)——Rotatable2DMap旋转2D地图

    目录 Cesium的Rotatable 2D Map示例展示了一个旋转的二维地图: 'use strict'; var viewer = new Cesium.Viewer('cesiumContai ...

  5. 一图看懂CodeArts Inspector 三大特性,带你玩转漏洞管理服务

    ​​​​本文分享自华为云开发者联盟公众号<一图看懂华为云CodeArts Inspector三大特性,带你玩转漏洞管理服务>. 华为云漏洞管理服务CodeArts Inspector是面向 ...

  6. 30秒,2种方法解决SQL Server的内存管理问题

    今天和大家聊一聊SQL server的内存管理,说之前我们需要先提出一个问题,SQL Server到底是如何使用内存的?弄清楚如何使用之后,才能谈如何管理. 简单说,SQL Server 数据库的内存 ...

  7. 如何处理分析Flink作业反压的问题?

    摘要:反压是 Flink 应用运维中常见的问题,它不仅意味着性能瓶颈还可能导致作业的不稳定性. 反压(backpressure)是实时计算应用开发中,特别是流式计算中,十分常见的问题.反压意味着数据管 ...

  8. 云图说|初识云数据库GaussDB(for Cassandra)

    摘要:不用再为数据不一致苦恼,因为强一致的Cassandra来了,DBA们不用加班修数据了.GaussDB(for Cassandra)是一款基于华为自主研发的计算存储分离架构的分布式云数据库服务,是 ...

  9. Seal 软件供应链防火墙 v0.2 发布,提供依赖项全局洞察

    Seal 软件供应链防火墙 v0.2 已于近日发布.这款产品旨在为企业提供代码安全.构建安全.依赖项安全及运行环境安全等4大防护,通过全链路扫描.问题关联及风险组织的方式保护企业软件供应链安全,降低企 ...

  10. Solon2 常用注解之 @Component 与 @Bean 的区别

    @Component 与 @Bean 设计的目的是一样的,都是注册 Bean 到容器里. 1.@Component 注解 及它的子类型 @Configuration,@Controller,@Remo ...