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 用户态内存泄漏

  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内存泄漏的更多相关文章

  1. Linux 内存泄漏 valgrind

    Valgrind 是个开源的工具,功能很多.例如检查内存泄漏工具---memcheck. Valgrind 安装: 去官网下载: http://valgrind.org/downloads/curre ...

  2. Linux 内存泄漏检查工具 valgrind

    抄自<从零开始的JSON库教程>,先mark一下,以后再慢慢研究. ======== 引用分割线 ======== 在 Linux.OS X 下,我们可以使用 valgrind 工具(用 ...

  3. Linux/Unix使用valgrind内存泄漏检测

    c\c++程序设计.内存管理是一个比较头疼的问题.相信它会导致内存泄漏.除了外部养成良好的编程习惯(使用智能指针),使用该工具还可以帮助检测内存泄漏,valgrind这是Unix\Linux在一个很好 ...

  4. 如何在linux下检测内存泄漏

    之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...

  5. 如何在linux下检测内存泄漏(转)

    本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 ...

  6. 【linux】linux下对java程序生成dump文件,并使用IBM Heap Analyzer进行分析,查找定位内存泄漏的问题代码

    1.首先,java程序启动在linux,怎么生成dump文件? 1>第一步,首先你需要得到java程序的PID,最简单的方法使用如下命令 ps -ef|grep java 或者如果是docker ...

  7. Linux下内存泄漏工具【转】

    转自:http://www.cnblogs.com/guochaoxxl/p/6970090.html 概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况 ...

  8. 在 Linux 平台中调试 C/C++ 内存泄漏方法(转)

    由于 C 和 C++ 程序中完全由程序员自主申请和释放内存,稍不注意,就会在系统中导入内存错误.同时,内存错误往往非常严重,一般会带来诸如系统崩溃,内存耗尽这样严重的后果.本文将从静态分析和动态检测两 ...

  9. Linux下内存泄漏工具

    概述 内存泄漏(memory leak)指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况,在大型的.复杂的应用程序中,内存泄漏是常见的问题.当以前分配的一片内存不再需要使用或无法访问时,但是却 ...

随机推荐

  1. 入门-k8s集群环境搭建(二)

    对于 Kubernetes 初学者,在搭建K8S集群时,推荐在阿里云或腾讯云采购如下配置:(您也可以使用自己的虚拟机.私有云等您最容易获得的 Linux 环境) 至少2台 2核4G 的服务器 Cent ...

  2. uni showLoading 还有注意关闭 闭包, .finally

    uni.showLoading({ title:'正在提交...' }); let data = JSON.parse(JSON.stringify($this.sendData)); const r ...

  3. sublime配置大全

    配置:Preferences→Settings-User 字体和字体大小 "font_face": "YaHei Consolas Hybrid", " ...

  4. 项目架构(结构)搭建:主流结构(UITabBarController + 导航控制器)

    /* 项目架构(结构)搭建:主流结构(UITabBarController + 导航控制器) -> 项目开发方式 1.storyboard 2.纯代码 */ @interface AppDele ...

  5. Windows系统禁止自动更新

    Windows + R键 输入services.msc(服务管理窗口) 找到Windows Update 停止且禁用 恢复->第一次失败 无操作 Windows + r 输入gpedit.msc ...

  6. suse 12 利用缓存创建本地源供内网服务使用

    文章目录 服务端获取 添加源 刷新源 清除缓存 安装软件 获取rpm包 客户端测试 zypper --help 前言: 其实,咱也不知道为啥写了这篇博客,咱就是想学一学suse,咱也不会,咱也只能学, ...

  7. python-利用pymysql获取数据简单使用总结

    python-利用pymysql获取数据库中的数据 1.前言 pymysql是一个第三方的模块,使用前需要安装 2.安装 pip install pymysql 3.基本使用 import pymys ...

  8. nessus安装破解

    Nessus2.0-20211012插件包 Nessus-8.15.2-x64.msi 0x01 Nessus更新介绍 Nessus下载地址 1https://www.tenable.com/down ...

  9. 思迈特软件Smartbi:利用大数据为产业赋能,且看这家风电巨头的实践之路!

    随着大数据技术成为各行各业转型升级的"新动能",数字化风电.智慧风电场也成为风电行业的高频词,大数据已经逐渐被用于风场从测风到运维的各个环节. Smartbi的某客户是国内风电装备 ...

  10. Ubuntu更新命令无法执行的,下一步该怎么办?

    对Linux的系统学习的更加深入,所以今天笔者正在Ubuntu20.04 LTS 上部署Sublime Text 的环境时 , 由于对操作的不熟悉,踩了一些坑.拿出来和大家分享. 正在我对照着官方文档 ...