一种内存泄露检查和定位的方法

一个系统后台服务进程,可能包括多个线程,在生成环境下要求系统程序能够稳定长时间稳定运行而不宕机。其中一个基本的前提就是需要保证系统程序不存在内存泄露。那么,该如何判读系统程序是否存在内存泄露呢?如果存在,又该如何检测呢?

0.判读系统程序是否存在内存泄露

对于频繁快速申请内存的应用,可以允许下面的命令:

top
-p `pidof YourProgrogram`

如果看到系统内存使用率一直上身,没有下降,就说明很可能存在内存泄露。

对于申请、使用内存比较缓慢的应用程序,可以通过下面的命令,观测一天乃至一周内内存使用率的变化:

for
((i=0;i<100000;i++)); do pidstat -p `pidof YourProgram` -tr | tee
-a thread_mem_static.txt; sleep 10; done

如果上面显示的RSS的内存随着时间推移不断增加,且不符合程序预期,那么很可能存在内存泄露。

1.定位内存泄露的线程或代码位置

检查主进程的每个线程的page
fault的频率,虽然page
fault频率高的不一定有内存泄露,但有内存泄露的线程的page
fault的频率一定很高。而体现每个线程Page
fault频率的指标就是上图中每个线程的minflt/s值,如果它的值一直偏高,就说明该线程反复申请内存或者不停在栈上使用buffer,此时就需要利用gdb打印出每个线程信息,可以参考下面的gdb命令:

gdb
-q --batch --ex "thread apply all bt" -p `pidof tmem`

根据上面对应的线程号找到相应函数,然后进行跟踪,可以参考下面的示例:

上图中显示线程14178
(mem_funcs)线程频繁使用新的内存,查看代码,果然存在内存泄露:

需要强调的是,只有RSS不一直增加,哪怕minflt/s一直增加,也表明没有内存泄露,比如下面的测试程序,频繁使用栈上空间:

void
internal_mem_funcs(void)

{

long
int test[MAX_BUF_LEN] = {0,};

//long
int * test = (long int *)malloc(MAX_BUF_LEN * sizeof(long int));

int
i = 0;

for
(i = 0; i < MAX_BUF_LEN; i++) {

test[i]
= random();

}

return;

}

它的pidstat统计图如下:

2.常见的内存泄露方式

笔者最近分析了一个系统服务进程内存泄露的问题,下面总结了一些代码中很容易出现内存泄露的地方:

  • 函数正常成功执行的时候有释放内存,但在执行异常退出的时候,没有释放所有先前申请的内存;

对类似strdup()/strndup()/g_strdup()的函数的返回值,使用完之后,没有释放内存的意识;

  • 不同模块或者层次的代码相互调用的时候,没有统一约定好是调用者申请内存、释放内存还是被调用者申请、释放内存,抑或是调用者申请/释放内存,被调用者释放/申请内存,导致后面遗忘释放内存或者重复释放内存;
  • Java/c++中对异常处理的流程中,遗忘没有释放内存;
  • 使用了一些不太熟悉的第三方库代码,对类似句柄、描述符、对象相关的API了解不够深入,导致没有也不知道该如何释放内存。
时间: 2024-12-24 07:56:02

一种内存泄露检查和定位的方法的相关文章

C++内存泄露的有效预防方法:谁使用,谁删除

内存泄露就是new出来的东西没有delete,我们可以这样:创建动态对象的人尽管使用new来创建对象:使用此对象的人负责释放此内存块. 例如:我和他人共享一个消息队列,他人将消息(new出来的对象)放到消息队列中,他不负责释放:我从消息队列里取消息,我一旦从消息队列里取出一个消息,消息队列里就不再有这个消息,消息的控制权和所有权都在我手上,我在用完之后就应该delete.这样就保证了代码编写的简单话,只要大家都尊周这个简单的方法就可以保证没有内存泄露. 再例如:ACE中有个ACE_Message

C++内存泄露问题定位经验案例

百度百科: 内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元.直到程序结束.(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏. 内存泄漏形象的比喻是"操作系统可提供给所有进程的存储空间正在被某个进程榨干",最终结果是程序运行时间越长,占用存储空间越来越多,最终用尽全部存储空间,整个系统崩溃.所以"内存泄漏"是从操作系统的角度来看的.这里的存储空间并不是指物理内存,而是指虚拟内

vld,Bounds Checker,memwatch,mtrace,valgrind,debug_new几种内存泄露检测工具的比较

概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却并没有释放它,这时就出现了内存泄漏.尽管优秀的编程实践可以确保最少的泄漏,但是根据经验,当使用大量的函数对相同的内存块进行处理时,很可能会出现内存泄漏. 内存泄露可以分为以下几类:1. 常发性内存泄漏.发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏.2. 偶发性内存泄漏.发生

C++内存泄露的有效预防方法:谁使用,谁删除 (1.2)

内存泄露就是new出来的东西没有delete,我们能够这样:创建动态对象的人虽然使用new来创建对象:使用此对象的人负责释放此内存块. 比如:我和他人共享一个消息队列,他人将消息(new出来的对象)放到消息队列中,他不负责释放:我从消息队列里取消息,我一旦从消息队列里取出一个消息,消息队列里就不再有这个消息,消息的控制权和全部权都在我手上,我在用完之后就应该delete.这样就保证了代码编写的简单话,仅仅要大家都尊周这个简单的方法就能够保证没有内存泄露. 再比如:ACE中有个ACE_Messag

避免内存泄露的一些简单方法

之前的文章中说到了Android的内存管理相关的原理,也能了解到Android Memory Leak 和 OOM为什么会发生.这次主要说说编码层面,如何来预防Memory Leak的发生. 对象都是有生命周期的,对象的生命周期有的是进程级别的,有的是Activity所在的生命周期,随Activity消亡:有的是Service所在的生命周期,随Service消亡.很多情况下判断对象是否合理存在的一个很重要的理由就是它实际的生命周期是否符合它本来的生命周期.很多Memory Leak的发生,很大程

分享几种CSS背景图片定位的方法

由于观测指标间存在相关性,将导致信息的重叠与低效,我们倾向于用少量的.尽可能多能反映原特征的新特征来替代他们,主成分分析因此产生.主成分分析可以看成是高维空间通过旋转坐标系找到最佳投影(几何上),生成新维度,其中新坐标轴每一个维度都是原维度的线性组合θ′Xθ′X(数学上),满足: 如果存在这么严重的问题,网络上应该早就有人遇到了.但实际上没有一个人提出类似的问题,并且我们使用的 jQuery 也是最新版:v1.12.4 为了避免 FineUIPro 的客户端 JavaScript 的影响,我们把

java内存泄露分析定位

线上服务模块CPU和RAM内存都出现了异常,记录一下自己的分析过程: 1.确定线上环境os是linux-debian9.3 2.确定web容器采用的是jetty9.4版本 3.先用top分析当前系统内存和cpu的占用情况 1)先top,然后m切换内存使用情况图表 top - 11:31:03 up 2 days, 14:51, 2 users, load average: 21.71, 20.58, 19.47 Tasks: 161 total, 1 running, 160 sleeping,

Tomcat内存泄露解决方法

环境: 今天早上,实施人员找我说,部署在tomcat上的一个项目总是间隔一段时间就自动关闭了,我询问一些可能发生的情况后,我就找了tomcat下的日志文件catalina.2015-04-13.log,localhost.2015-04-13.log这两文件,经过一番查找后,看到了下面一段 异常详细信息介绍: http://confluence.atlassian.com/pages/viewpage.action?pageId=218275753 原因大概是说tomcat 6.025之后引入了

Android 内存泄露总结(附内存检测工具)

https://segmentfault.com/a/1190000006852540 主要是分三块: 静态储存区:编译时就分配好,在程序整个运行期间都存在.它主要存放静态数据和常量. 栈区:当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存. 堆区:通常存放 new 出来的对象.由 Java 垃圾回收器回收. 栈与堆的区别 栈内存用来存放局部变量和函数参数等.它是先进后出的队列,进出一一对应,不产生碎片,运行效率稳定高.当超过变量的作用域后,该变量也就无效了,分配给它