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)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...
随机推荐
- DOM Document.readyState 属性
感谢原文作者:MDN 原文地址:https://developer.mozilla.org/zh-CN/docs/Web/API/Document/readyState 描述 一个document 的 ...
- Window 共享内存
转载请注明来源:https://www.cnblogs.com/hookjc/ C++使用共享内存实现进程间通信文件映射是一种实现进程间单向或双向通信的机制.它允许两个或多个本地进程间相互通信.为了共 ...
- linux 设置connect 超时代码[select/epoll]
转载请注明来源:https://www.cnblogs.com/hookjc/ linux下socket编程有常见的几个系统调用: 对于服务器来说, 有socket(), bind(),listen( ...
- Spark RDD学习
RDD(弹性分布式数据集)是Spark的核心抽象.它是一组元素,在集群的节点之间进行分区,以便我们可以对其执行各种并行操作. 创建RDD的两种方式: 并行化驱动程序中的现有数据: 引用外部存储系统中的 ...
- 实现redis哨兵,模拟master故障场景
由于主从架构无法实现master和slave角色的自动切换,所以在发送master节点宕机时,redis主从复制无法实现自动的故障转移,即将slave 自动提升为新的master.因此,需要配置哨兵来 ...
- PyCharm编程软件详细安装教程
PyCharm编程软件安装教程&破解 一.官网下载软件 1. 网页搜索进入PyCharm官网下载页面(https://www.jetbrains.com/pycharm/download/ ) ...
- Linux基础:VLAN篇
一.二层基础知识 1.1 vlan介绍 本小节重点: vlan的含义 vlan的类型 交换机端口类型 vlan的不足 1.1.1 vlan的含义 局域网LAN的发展是VLAN产生的基础,因而先介绍一下 ...
- Solution -「APIO 2016」「洛谷 P3643」划艇
\(\mathcal{Description}\) Link & 双倍经验. 给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...
- MYSQL数据表损坏的原因分析和修复方法小结
MYSQL数据表损坏的原因分析和修复方法小结 1.表损坏的原因分析 以下原因是导致mysql 表毁坏的常见原因: 1. 服务器突然断电导致数据文件损坏. 2. 强制关机,没有先关闭mysql 服务. ...
- 面试突击24:为什么wait和notify必须放在synchronized中?
在多线程编程中,wait 方法是让当前线程进入休眠状态,直到另一个线程调用了 notify 或 notifyAll 方法之后,才能继续恢复执行.而在 Java 中,wait 和 notify/noti ...