利用进程信息追查内存泄漏

dump heap及分析内存泄漏 服务范围 阅读详情

一、问题现象

Bigpipe是Baidu公司内部的分布式传输系统,其服务器模块Broker采用异步编程框架来实现,并大量使用了引用计数来管理对象资源的生命周期和释放时机。在对Broker模块进行压力测试过程中,发现Broker长时间运行后,内存占用逐步变大,出现了内存泄漏问题。

二、初步分析

针对近期Broker的升级改造点,确定Broker中可能出现内存泄漏的对象。Broker新增了监控功能,其中一项是对服务器各个参数的监控统计,这必然对参数对象有读取操作,每次操作都将引用计数“加一”,并在完成操作后“减一”。当前,参数对象有数个,需要确定是哪个参数对象泄漏了。

三、代码&业务分析

1.     为证明之前的初步分析的结果,可能的方法有是:使用Valgrind运行Broker并启动压力程序复现可能的内存泄漏。但是,使用这种方法:

1)    由于内存泄漏的触发条件并不简单,可能导致复现周期很长,甚至无法复现同样的内存泄漏;

2)    内存泄漏的对象放置在容器中,valgrind正常退出后不报告相关的内存泄漏;

经过另外的测试集群短时间的运行尝试进行复现,果然Valgrind报告未出现异常。

2.     分析现有拥有的条件:幸好,出现“内存泄漏”问题的Broker进程仍然在运行中,真相就在这个进程内部。应该充分利用已有的现场,完成问题的定位。初步希望使用GDB调试。

3.     挑战:使用GDB attach pid的方法将会导致进程挂起,按Broker的设计,一当配对另一个主/从Broker不互相发送心跳, Broker也将自动退出程序,退出后现场就无法保存,这意味着使用GDB的机会只有一次。

4.     方案:利用gdb打印内存信息并从信息中观察可能的内存泄漏点。

5.     步骤一:pmap -x {PID}查看内存信息(如:pmap -x 24671);得到类似如下信息,注意标记为anon的位置:


6.     步骤二:启动gdb ./bin/broker并使用 attach {PID}命令加载现有进程;例如上述进程号为24671,则使用:attach 24671;

7.     步骤三:使用setheight 0和 setlogging on开启gdb日志,日志将存储于gdb.txt文件中;

8.     步骤四:使用x/{内存字节数}a {内存地址} 打印出一段内存信息,例如上述的anon为堆头地址,占用了144508kb内存,则使用:x/18497024a0x000000000109d000;若命令行较多,可以在外围编辑好命令行直接张贴至gdb命令行提示符中运行,或者将命令行写到一个文本文件中,例如command.txt中,然后再gdb命令行提示符中使用sourcecommand.txt来执行文件中的命令集合,下面是command.txt文件的内容;


9.     步骤五:分析gdb.txt文件中的信息,gdb.txt中的内容如下:


Gdb.txt中内容的说明和分析:第一列为当前内存地址,如0x22c2f00;第二、三、四列分别为当前内存地址对应所存储的值(使用十六进制表示),以及gdb的debug的符号信息,例如:0x10200d0<_ZTVN7bigpipe15BigpipeDIEngineE+16> 0x4600000001,分别表示:“前16字节”、“符号信息(注意有+16的偏移)”、“后16字节”,但不是所有地址都会打印gdb的debug符号信息,有时符号信息显示在第三列,有时显示在第二列。上述这行内存地址0x22c2f00 存储了bigpipe::BigpipeDiEngine 类的生成的其中一个对象的虚析构函数的函数指针,即虚函数表指针(vptr),其中地址0x10200d0附近内存存储的应该是BigpipeDiEngine类的虚函数表(vtbl),如下所示:


地址0x10200d0中的值是指向BigpipeDiEngine类的析构函数的地址,即真正的析构函数代码段头地址0x53e2c6。可以从上述执行结果看到,地址0x53e2c6的“符号信息”是析构函数名<bigpipe::BigpipeDIEngine::~BigpipeDIEngine()>,其汇编命令为push。因此,可以知道最初看到的0x22c2f00地址是对象的一个虚析构函数指针,并且有“符号信息”BigpipeDIEngine显示出来,可以根据这种信息确定出这个类(带虚析构函数的类)生成了多少个实例,然后根据排出来的实例个数做进一步判断。

因此,对gdb.txt排序并做适当处理获得符号(类名/函数名称)出现的次数的列表。例如将上述内容过滤出带尖括号的“符号信息”部分并按出现次数排序,可以使用类似如下命令,catgdb.txt |grep "<"|awk -F '<' '{print $2}' |awk -F '>''{print $1}' |sort |uniq -c|sort -rn > result.txt,过滤出项目相关的变量前缀(如bmq、Bigpipe、bmeta等)cat result.txt|grep -P"bmq|Bigpipe|bigpipe|bmeta"|grep "_ZTV" > result2.txt,获得类似如下的列表:


10.  然后找出和本工程项目相关的且出现次数最多的为CConnect对象;判断出可能泄漏的对象后,还需要定位在异步框架下,哪个引用计数出现了问题导致CConnect对象无法正常减一并得到释放。

11.  经过追查新增的“监控”功能与CConnect相关的代码,如下。


四、真相大白

查看atomic_add函数的实现(如下),可以得知,返回值是自增(减)之前的值,而由于函数名称atomic_add并未特别的表现出这样的含义,导致调用者误用了这个函数,认为是自增之后的值,最终引用计数误认为不为0,导致未执行_free操作,进而导致内存泄漏。通常,和__sync_fetch_and_add对应的函数还有__sync_add _and_fetch,这两者的区别在于“先获得值再加”还是“先加值在获取”。


五、解决方案

因此,程序的改进如下:


六、总结

1.    由于异步框架实现的程序对问题定位跟踪难度较高,需要综合:日志,gdb,pmap等手段完成问题复现和定位;

2.    Valgrind检测内存泄漏并不是唯一的方法,且具有一定的局限性;

3.    函数名称定义尽量直观表明函数功能,能够避免调用方的一部分错误;

4.      应当仔细阅读库函数的说明文档,了解使用方法;

5.      本方法运用的场景和局限:1)使用gdb打印内存信息中,必须符合实例数和内存信息符号有一对一关系的情形,上述实践中CConnect类有虚析构函数,因此在内存信息中能查看到虚函数表指针,且和出现的符号有一一对应的关系,由此能作为内存泄漏存在于此类的推测条件;若泄漏的内存在内存信息中没有留下“痕迹”则无法获得内存泄漏的有效信息;2)在线下尝试内存泄漏复现失败后,但有内存泄漏的进程(现场)在线上仍然存在,可以尝试使用上述方法,从已有的进程(现场)中更多获取内存泄漏信息;3)此方法可以利用现有的已经产生内存泄漏的进程(现场)进行分析,充分利用了已有的问题进程;4)上述方法作为其他内存泄漏调试方法的一种补充,一种值得尝试的方法,可以作为参考。

程序调试利器——GDB使用指南 GDB是探查查询运行中各种疑难问题的利器。在实际应用中,问题产生的原因通常要复杂得多。程序可能在标准库中产生了Crash,整个堆栈可能都是标准库代码;程序可能由于我们的代码的操作,最终在三方中间件中产生了问题;整个异常堆栈可能都不包含我们自己开发的代码;面对被三方库不知以何种方式使用的变量。我们除了需要熟悉GDB的使用之外,在这些复杂的实际问题上,我们还需要尽可能多地了解我们使用的其它库的机制和原理。下方这份完整的软件测试视频学习教程已经整理上传完成,朋友们如果需要可以自行免费领取【保证100%免费】 阅读详情

相关推荐

Android开发————分析Native层内存泄漏

Android开发——使用DDMS分析Native层内存泄漏针对Java层的内存泄漏,Android提供了方便的内存泄漏检测工具,例如MAT、LeakCanary。但对于native层开发,要追查C/C++代码的内存泄漏,valgrind等常用工具并不适用。幸好,Google的bionic库提供了新的方法。下面就介绍如何利用DDMS分析Native层的内存泄漏。检查是否有 libc_malloc_d

u010307119的博客 2万+

gdb如何调试内存泄漏问题

修复内存泄漏问题:通过分析内存分配和释放信息,找到内存泄漏的位置和原因后,可以对程序进行修改,释放未释放的内存,从而修复内存泄漏问题。命令监视特定的内存地址,当它被修改时,GDB 会自动停止程序执行,并提供调试信息。命令可以查看程序中所有的内存分配情况,包括已分配的内存块和未释放的内存块。命令输出的信息,分析哪些内存块没有被释放,以及它们在哪里分配的。命令运行程序,并在程序运行过程中记录内存分配和释放的信息。观察内存分配和释放信息:在程序运行过程中,使用 GDB 的。命令,可以帮助定位内存泄漏的问题。

liu995336126的博客 5547

iPhone开发Swift基础07 内存泄漏检测

Instruments Instruments工具是用于动态跟踪和分析代码的工具,可以跟踪一个或者多个进程,并检测收集实时数据,使开发者更好地理解应用程序和操作系统的行为和性能。 追查代码中难以重现的问题 对应用程序进行性能分析 自动化测试应用程序中的代码 对应用程序进行压力测试 进行一般的系统级故障诊断 对应用程序的代码如何工作有更加深入的了解 Allocations Instruments中的Allocations工具可以显示内存中的对象占用曲线,内存当前都分配给那些对象、被分配内存对象数量以及由哪

乐事派的专栏 2038

Linux中anonpage内存,Linux物理内存概述

Linux可以支持大量的架构,所以需要用一种与架构无关的方式去描述内存。在linux的内存管理中,我们首先要明确的一个概念就是NUMA(Non-Uniform Memory Access,关于NUMA的介绍可以参考我前面的文章)。很多大型机器都采用NUMA架构,将内存和CPU分为很多组,每一组称为一个节点(node)。节点与节点之间的互相访问,会因为“距离”的不同导致不同的开销。Linux通过st...

weixin_39926402的博客 2351

php源码之路第六章第六节 ( 内存泄漏)

内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象,对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序,比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升,可能会因为占用内存过高而崩溃,或被系统杀掉(OOM)。 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放

Leslie 993

GDB查找内存泄露

后台程序中经常会存在一部分内存泄露,但是不能很好的定位造成内存泄露的代码,并进行修改,内存泄露不进行修改就会造成程序运行时占用的内存不断升高,逐渐的导致系统的不稳定,现将前一段时间通过GDB调试工具查找内存泄露的方法形成文档以便后续如果发现程序内存泄露能够方便的进行查找修改程序,使程序能够恢复到稳定,健壮运行.

如何自己检查NodeJS的代码是否存在内存泄漏

如何自己检查NodeJS的代码是否存在内存泄漏目录追踪NodeJS代码中的内存泄漏一直是一个很有挑战的难题。本文讨论如何从一个node写的应用里自动的跟踪到内存泄漏问题,在这里笔者向大家推荐两款追查内存问题的神器 —— memwatch 和 heapdump首先,我们来看一个简单的内存泄漏var http = require('http');var server = http.createServe

wflowho的博客 1360

零信任架构实战:“持续验证+动态授权”全流程解析(附策略引擎联动图)

《零信任实战指南:7图拆解核心流程与行业案例》摘要:本文通过7张架构图系统解析零信任五大核心流程:强身份认证、设备检查、动态授权、持续监控和自动降权。对比金融(重数据审计)与制造业(重物理绑定)的落地差异,指出三大常见误区及解决方案。数据显示,零信任可使安全响应提速60%,泄露成本降低45%。文章提供6个月实施路线图,强调零信任是"智能信任"体系,建议企业分阶段改造,优先保护核心系统。附赠金融/制造行业策略模板及甘特图示例。(149字)

sara_han的博客 773

内存泄漏

内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象, 对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序, 比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升, 可能会因为占用内存过高而崩溃,或被系统杀掉(OOM)。 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内...

weixin_30319097的博客 259

如何在n8n中高效调用playwright-mcp实现浏览器自动化(附避坑指南)

本文详细介绍了在n8n中高效集成playwright-mcp实现浏览器自动化的全流程指南,包括环境准备、工作流设计与优化、高级技巧与性能调优以及调试与问题排查。通过克服实际部署中的各种挑战,帮助用户打造稳定高效的自动化解决方案,特别适合需要浏览器自动化的工作流场景。

weixin_30379531的博客 387

Seurat 单细胞转录组测序数据分析教程(三)——python(scanpy)

文章参考至,做了一个更详细的解读。本教程探讨了 scanpy 的可视化可能性,分为三个部分:嵌入的散点图(例如 UMAP、t-SNE)使用已知标记基因鉴定簇差异表达基因的可视化在本教程中,我们将使用来自 10x 的数据集,其中包含来自PBMC的 68k 个细胞。Scanpy 在其分布中包括该数据集的简化样本,该数据集仅包含 700 个细胞和 765 个高度可变的基因。该数据集已经过预处理和 UMAP 计算。在本教程中,我们还将使用以下文献标记:B细胞:CD79A、MS4A1。

coffeeii的博客 5827

单多线程diff问题追查

1.问题背景 运行于一个进程中的多个线程,彼此之间使用相同的地址空间,共享大部分数据,因此启动一个线程所花费的空间远远小于启动一个进程所花费的空间,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间,一个线程的开销大约是一个进程的开销1/30左右,但是其公共数据共享可能会带来灾难性的后果,最常见的是共享变量的互斥、变量同步问题。测试中通过对比单线程与多线程执行结果进行的一致性,来发现多线程

lwnylslwnyls的专栏 1564

计算机视觉(相机标定;内参;外参;畸变系数)

目录 一、预备知识 1、坐标系变换过程(相机成像过程) (1)相机坐标系转换为图像坐标系(透视投影变换遵循的是针孔成像原理) (2)齐次坐标的引入原因:(为什么引入齐次坐标???) 2、内参与外参矩阵的构成 3、畸变参数 二、相机标定 1、张正友标定法(光学标定)及其求解思路 2、求解内参矩阵与外参矩阵的思路: (1)计算内参与外参矩阵的乘积M (2)求解内参矩阵A (3)求解外参矩阵(R1 R2 T) 三、参数优化 1、L-M算法 2、相机标定步骤 四、相关代码及其实验结.

QYJ_WORKHARDING的博客 6万+

PHP的内存泄漏及解决方法

内存泄漏指的是在程序运行过程中申请了内存,但是在使用完成后没有及时释放的现象, 对于普通运行时间较短的程序来说可能问题不会那么明显,但是对于长时间运行的程序, 比如Web服务器,后台进程等就比较明显了,随着系统运行占用的内存会持续上升, 可能会因为占用内存过高而崩溃,或被系统杀掉(OOM)。 PHP的内存泄漏 PHP属于高级语言,语言级别并没有内存的概念,在使用过程中完全不需要主动申请或释放内...

编程不过是一门失传艺术的别名,这门艺术的名字叫做“思考” 1381

【AI大模型应用开发】教你用AI轻松将你的知识库变为知识图谱(附完整代码,直接运行)

本文我们来介绍如何使用AI,将自己的知识库自动转换为知识图谱,并进行可视化展示。

同学小张的博客 3925

优快云独家首发!万字长文,YOLOv5/v7/v8算法模型yaml文件史上最详细解析与教程!小白也能看懂!掌握了这个就掌握了魔改YOLO的核心!

🍀🍀🍀YOLOv5/v7/v8算法模型yaml文件史上最详细解析与教程,全网最强,学不会算我输!!!

Coding... 1万+

java 进程100_Java进程CPU占用率100%问题排查的方法

本篇文章给大家带来的内容是关于Java进程CPU占用率100%问题排查的方法,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。100%指的是占用了CPU一个核心,两个核心是200%,以此类推。CPU占用率及对应进程ID(pid)可以通过top命令确定,在top界面按 c (显示完整的命令行参数),按 1 (显示每个核心的统计数据)。(推荐:Java教程)这个问题最常见的有以下几种可能...

weixin_29668665的博客 421

VisionPro - 基础 - 模板匹配技术-Search/PMAlign/PatMax(6)-纹理屏蔽和重叠匹配

Note:对已经有了,1已经训练好的模板,2一组使能的自由度,3一个待测的实时图片,PatMax 就能模板匹配的给出变化的最佳描述。对一些综合的模板,这三个输入值往往是一起影响最后的变换结果信息。例如,如果我们训练了一个圆形的模板,然后搜索一个角度自由度包括一个圆,那么将会有无限个可能的角度满足要求。这些组合的模板匹配,被官方名为:退化系统,a degenerate system的结果被叫做a degenerate result 退化结果4.2 退化系统例子。

山云的专栏 1532

java 进程100_Java进程CPU占用率100%问题排查

100%指的是占用了CPU一个核心,两个核心是200%,以此类推。CPU占用率及对应进程ID(pid)可以通过top命令确定,在top界面按 c (显示完整的命令行参数),按 1 (显示每个核心的统计数据)。这个问题最常见的有以下几种可能:1、堆内存不足导致频繁Full GC可以通过两个命令确定sudo jmap -heap pid 查看堆内存的消耗情况sudo jstat -gc pid int...

weixin_32734545的博客 389

【OpenClaw从入门到精通】第20篇:OpenClaw实战—从零搭建教育自动化助教系统(作业批改+智能答疑+学情分析)【2026实测】

本文基于OpenClaw开源框架,聚焦教育行业“答疑重复、批改耗时、学情模糊”三大核心痛点,提供从环境部署到功能落地的全流程实操方案。通过整合QQ群交互、代码分析、数据可视化等技能,构建“智能答疑+作业批改+学情分析”的自动化助教系统。系统支持7×24小时群聊答疑、多语言作业自动评审、学情数据周报生成,经实测可使助教工作时间减少60%、作业批改效率提升5-10倍、学情问题识别提前5周。文中包含完整配置步骤、可直接运行的代码示例及避坑指南,兼顾新手入门与进阶实操,帮助教育工作者快速落地自动化工具,从重复劳动中

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1448

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

JAVACPU占用过高、内存泄漏问题排查——HttpClient占用过多buffer

问题起因: java工程消费的内容延迟严重,发现负责消费的dispatcher 进程阻塞,且占用的CPU%很高。 开始按照https://www.cnblogs.com/paul8339/p/7464206.html文中提到的方法排查。 一、追查 重点: 如果java进程在docker下执行,需要进入docker里边执行下面的步骤,否则会报错: Unable to open sock...

wangyueshu的博客 6763

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

追踪和定位内存泄漏

一、问题现象Bigpipe是Baidu公司内部的分布式传输系统,其服务器模块Broker采用异步编程框架来实现,并大量使用了引用计数来管理对象资源的生命周期和释放时机。在对Broker模块进行压力测试过程中,发现Broker长时间运行后,内存占用逐步变大,出现了内存泄漏问题。二、初步分析针对近期Broker的升级改造点,确定Broker中可能出现内存泄漏的对象。Broker新增了监控功能,其中一项...

runner668的博客 898

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

java计算进程cpu占用率_Java进程CPU占用率100%问题排查

100%指的是占用了CPU一个核心,两个核心是200%,以此类推。CPU占用率及对应进程ID(pid)可以通过top命令确定,在top界面按 c (显示完整的命令行参数),按 1 (显示每个核心的统计数据)。这个问题最常见的有以下几种可能:1、堆内存不足导致频繁Full GC可以通过两个命令确定sudo jmap -heap pid 查看堆内存的消耗情况sudo jstat -gc pid int...

weixin_29095587的博客 406
上一篇: gdb 调试无堆栈??---pthread_join coredump
下一篇: linux 写时拷贝
linux_vae
博客等级 码龄15年 48粉丝 44原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值