Linux内存泄漏
0 什么是内存泄漏?
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
1 常见的造成内存泄漏的原因
1.1 指针重新赋值
下面是一段示例代码:
char * p = (char *)malloc(10);
char * np = (char *)malloc(10);
其中,指针变量p和np分别被分配了10个字节的内存,它们各自的内存如图所示

如果程序执行如下赋值语句:
p=np;
这时候,指针变量p被np指针重新赋值,其结果是p以前所指向的内存位置变成了孤立的内存,如图所示。它无法释放,因为没有指向该位置的引用,从而导致 10 字节的内存泄漏。

因此,在对指针赋值前,一定确保内存位置不会变为孤立的。
1.2 错误的内存释放
假设有一个指针变量 p,它指向一个10字节的内存位置。该内存位置的第三个字节又指向某个动态分配的 10 字节的内存位置,如图所示。

如果程序执行如下语句:
free(p);
很显然,如果通过调用 free 来释放指针 p,则 np 指针也会因此而变得无效。np 以前所指向的内存位置也无法释放,因为已经没有指向该位置的指针。换句话说,np 所指向的内存位置变为孤立的,从而导致内存泄漏。
因此,每当释放结构化的元素,而该元素又包含指向动态分配的内存位置的指针时,应首先遍历子内存位置(如本示例中的 np),并从那里开始释放,然后再遍历回父节点,如下面的代码所示:
free(p->np);
free(p);
1.3 返回值的不正确处理
有时候,某些函数会返回对动态分配的内存的引用,如下面的示例代码所示:
char *f()
{
return (char *)malloc(10);
}
void f1()
{
f();
}
很明显,函数 f1 中对 f 函数的调用并未处理该内存位置的返回地址,其结果将导致 f 函数所分配的 10 个字节的块丢失,并导致内存泄漏。
1.4 内存malloc()分配后忘记使用free()进行释放
1.5 使用open()、fopen()后忘记使用close()、fclose()
2 内存泄漏的表现
2.1 应用程序崩溃
因为内存泄漏导致已运行的应用程序得不到所需的内存空间而出现崩溃。
2.2 内存占用量持续增长不减
内存泄漏会导致被泄露的内存在本次系统运行期间不能被使用,因此,随着时间的推移,内存占用量是持续增长的。
2.3 触发OOM,进程被kill
当系统无法为新进程分配内存时,可能会触发OOM,系统选择一些进程,然后kill他们。
3 如何定位内存泄漏
3.1 用户态内存泄漏
- 使用top指令查看系统中占用内存量较高的进程
top

观察以下参数:
VIRT 进程使用的虚拟内存
RES 进程使用的真实内存
SHR 共享内存
%MEM 内存占用率
M 按内存占用率(%MEM)排序

2. 找出内存占用量较高的进程后,记下该进程的PID,如上图的609。
3. 执行如下指令查看进程内存方面的详细信息。
watch -n 1 cat "/proc/"`ps -ef | grep PID | grep -v grep | awk 'NR==1 {print $2}'`"/status"

我们主要查看一下几个参数的值:
VmPeak:进程使用的虚拟内存的峰值
VmSize:进程当前使用的虚拟内存的大小
VmLck:已锁住的物理内存的大小(不能交换到磁盘)
VmHWM:进程使用的物理内存的峰值
VmRSS:进程当前使用的物理内存的大小
如果VmSize或VmRSS在一段时间内占用异常,可以考虑该进程是否存在内存泄漏。
4. 借助内存泄漏分析工具进行分析
推荐使用内存泄漏分析工具--valgrind
valgrind --tool=memcheck --leak-check=full xxx //xxx为该进程的二进制可执行文件的绝对路径
执行完毕后我们要观察的主要是如下图的信息:

Definitely lost:确认丢失,程序中存在内存泄漏,需要尽快修复。
Indirectly lost:间接丢失,常与definitely lost一起出现,只要修复definitely lost即可。
Possibly lost:可能丢失,大多数情况下应视为definitely lost,需要尽快修复。
Still reachable:可以访问的,这些内存没有丢失、没有释放。建议修复。
Suppressed:已解决的,可以无视此部分。
5. 假如有内存泄漏,则需要找出源码进行修复。
那如何快速定位是哪个位置出现了内存泄漏呢?
根据valgrind的打印信息快速定位。举例如下:

这个例子就说明了/root目录下的a.out程序存在4字节的内存泄漏,即test()函数里面的new操作存在泄漏,即new完没有对应的delete。(从下往上执行)
找到泄漏的原因,我们就可以在源码中找到对应的位置进行修复。
6. valgrind也不是万能的,存在如下缺点(包括但不限于):
1. valgrind会占用了更多的内存--会达到检测程序的两倍
2. valgrind不检查静态分配数组的使用情况
3. valgrind检测时新启动了一个进程,不能监测正在运行的进程
3.2 内核态内存泄漏
对于内核态内存泄漏的排查方法和工具,我不了解。如有好的参考资料可以评论区留言,谢谢各位dalao。
本文持续更新
Linux内存泄漏的更多相关文章
- Linux 内存泄漏 valgrind
Valgrind 是个开源的工具,功能很多.例如检查内存泄漏工具---memcheck. Valgrind 安装: 去官网下载: http://valgrind.org/downloads/curre ...
- Linux 内存泄漏检查工具 valgrind
抄自<从零开始的JSON库教程>,先mark一下,以后再慢慢研究. ======== 引用分割线 ======== 在 Linux.OS X 下,我们可以使用 valgrind 工具(用 ...
- Linux/Unix使用valgrind内存泄漏检测
c\c++程序设计.内存管理是一个比较头疼的问题.相信它会导致内存泄漏.除了外部养成良好的编程习惯(使用智能指针),使用该工具还可以帮助检测内存泄漏,valgrind这是Unix\Linux在一个很好 ...
- 如何在linux下检测内存泄漏
之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...
- 如何在linux下检测内存泄漏(转)
本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 ...
- 【linux】linux下对java程序生成dump文件,并使用IBM Heap Analyzer进行分析,查找定位内存泄漏的问题代码
1.首先,java程序启动在linux,怎么生成dump文件? 1>第一步,首先你需要得到java程序的PID,最简单的方法使用如下命令 ps -ef|grep java 或者如果是docker ...
- Linux下内存泄漏工具【转】
转自:http://www.cnblogs.com/guochaoxxl/p/6970090.html 概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况 ...
- 在 Linux 平台中调试 C/C++ 内存泄漏方法(转)
由于 C 和 C++ 程序中完全由程序员自主申请和释放内存,稍不注意,就会在系统中导入内存错误.同时,内存错误往往非常严重,一般会带来诸如系统崩溃,内存耗尽这样严重的后果.本文将从静态分析和动态检测两 ...
- Linux下内存泄漏工具
概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...
随机推荐
- C字符串倒置-中部对称
问题如图 Code #include<stdio.h> #include<string.h> #define MAX_LENGTH 10//最大字符串长度 void inver ...
- fckeditor for php 上传图片文件名中文乱码,中文文章乱码
转载请注明来源:https://www.cnblogs.com/hookjc/ 中文名乱码是因为:FCKeditor使用UTF-8编码,自己机子比如是Windows系统文件名使用的是GBK编码,在上传 ...
- eclipse使用的步骤
eclipse使用的步骤: 第一步: 选择工作目录. 以后在Eclipse上面写的所有代码都是在工作目录上的. 第二步: 在Project Exploer 窗口上创建一个工程,以后我们写代码都是以工程 ...
- STP的究极进化MSTP
MSTP多生成树协议 1.MSTP概述 2.MSTP相关配置命令 1.MSTP是一个公有生成树协议,在实际生产环境中得到了广泛的应用. PVST是思科私有的,它能让多实例,多VLAN可以进行负载均衡, ...
- 服务器硬件及RAID配置实践
服务器硬件及RAID配置实践 1.RAID磁盘阵列介绍 2.创建RAID磁盘阵列 1.RAID:中文简称为独立冗余磁盘阵列 把多块独立的物理硬盘按不同的方式组合起来形成一个硬盘组(逻辑硬盘),从而提供 ...
- JUC并发工具类之 CyclicBarrier同步屏障
首先看看CyclicBarrier的使用场景: 10个工程师一起来公司应聘,招聘方式分为笔试和面试.首先,要等人到齐后,开始笔试:笔试结束之后,再一起参加面试.把10个人看作10个线程,10个线程之间 ...
- 树莓派PICO刷入MicroPython内核的两种方式
一.MicroPython简介 MicroPython 是 Python 3编程语言的精简高效实现,其中包括 Python 标准库的一小部分,并且经过优化,可在微控制器和受限环境中运行. 可以在 25 ...
- Bypass BeaconEye - Beacon 堆混淆
这是[信安成长计划]的第 9 篇文章 关注微信公众号[信安成长计划] 0x00 目录 0x01 CS4.5 Sleep_Mask 0x02 HeapEncrypt 0x03 效果 0x04 参考文章 ...
- [Python]小白入门时遇到的各种问题
Q:关于Python2.X和Python3.X各种版本有什么区别,小白应该选哪个? A: 1.背景及简要介绍 Python 2 发布于 2000 年年底. 随着 Python 2 的不断发展,更多的功 ...
- windev中字符串分隔符的选择以及Contains使用技巧
字符串分隔符,理论上可以使用任意符号,但作为数据保存,建议只使用以下三种: 1.:分号 2.TAB制表符 3.CR换行符 主要有以下几个原因: 1.组织架构组件,获得的组织路径,使用TAB键分隔,TA ...