内存泄露简介

什么是内存泄漏

  内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因,程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
  内存泄漏缺陷具有隐蔽性、积累性的特征,比其他内存非法访问错误更难检测。因为内存泄漏的产生原因是内存块未被释放,属于遗漏型缺陷而不是过错型缺陷。此外,内存泄漏通常不会直接产生可观察的错误症状,而是逐渐积累,降低系统整体性能,极端的情况下可能使系统崩溃。

内存泄露产生的方式

以产生的方式来分类,内存泄漏可以分为四类:

  • 常发性会内存泄漏:发生内存泄漏的代码会被多次执行到,每次被执行时都导致一块内存泄漏。
  • 偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
  • 一次性内存泄漏:发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
  • 隐式内存泄漏:程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。

Valgrind

简介

  Valgrind具是一个用于调试和分析Linux程序的GPL系统。使用Valgrind的工套件,您可以自动检测许多内存管理和线程错误,使程序更稳定。还可以执行详细的分析以帮助加速程序的执行。
  Valgrind是Julian Seward的作品。Valgrind是运行在Linux上一套基于仿真技术的程序调试和分析工具,它包含一个内核,一个软件合成的CPU,和一系列的小工具。如下图所示:

安装

  CentOS安装:

# sudo yum install valgrind -y

  Ubuntu 安装:

# sudo apt install valgrind -y

示例程序

  给出一个简单示例malloc.c 。

#include<stdio.h>
#include<stdlib.h>
void fun()
{
int *x = malloc( * sizeof(int));
x[] = ;
}
int main()
{
int i = ;
fun();
printf("i = %d\n",i);
return ;
}

  以上代码存在两个问题:

  • 没有free掉申请的资源;
  • fun函数里面越界了,x[10]是非法的。

Memcheck

  是最常用的小工具,用来检测程序中出现的内存问题,所有对内存的读写都会被检测到,一切对malloc和free的调用都会被捕获,它能检测下列问题:

  • 对未初始化内存的使用;
  • 读/写释放后的内存块;
  • 读/写超出malloc分配的内存块;
  • 读/写不适当的栈中的内存块;
  • 内存泄漏,指向一块内存的指针永远丢失;
  • 不正确的malloc/free或new/delete匹配;
  • memcpy相关函数中的dst和src指针重叠;

  我们使用Memcheck小工具来检测存在的问题。
  编译:gcc -Wall -o malloc malloc.c
  检测:valgrind ./malloc
    --show-reachable=<yes|no> [default: no]
    --leak-check=full 查看更为详细信息

  其中,34496是程序运行时的进程号。
  Invalid write of size 4:表示非法写入(越界),下面是告诉我们错误发生的位置,在main中调用的fun函数。
  HEAP SUMMARY:说明了堆的情况,可以看到申请了40个字节,后面说有1个申请,0个被free。
  LEAK SUMMARY:也是说的堆的泄漏情况,明显丢失的有40个字节。
  如果main中的i未初始化,这里还会有一些其他的错误。

# gcc -Wall -o malloc malloc.c
malloc.c: In function ‘main’:
malloc.c::: warning: ‘i’ is used uninitialized in this function [-Wuninitialized] # 未初始化变量
printf("i = %d\n",i);
^
[root@localhost memcheck]# valgrind ./malloc
==== Memcheck,a memory error detector
==== Copyright (C) -,and GNU GPL'd,by Julian Seward et al.
==== Using Valgrind-3.13. and LibVEX; rerun with -h for copyright info
==== Command: ./malloc
====
==== Invalid write of size
==== at 0x40057B: fun (in /root/memcheck/malloc)
==== by 0x400594: main (in /root/memcheck/malloc)
==== Address 0x5203068 is bytes after a block of size alloc'd
==== at 0x4C29BC3: malloc (vg_replace_malloc.c:)
==== by 0x40056E: fun (in /root/memcheck/malloc)
==== by 0x400594: main (in /root/memcheck/malloc)
====
==== Conditional jump or move depends on uninitialised value(s)
==== at 0x4E80B9E: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
==== Use of uninitialised value of size
==== at 0x4E7E26B: _itoa_word (in /usr/lib64/libc-2.17.so)
==== by 0x4E824F0: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
==== Conditional jump or move depends on uninitialised value(s)
==== at 0x4E7E275: _itoa_word (in /usr/lib64/libc-2.17.so)
==== by 0x4E824F0: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
==== Conditional jump or move depends on uninitialised value(s)
==== at 0x4E8253F: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
==== Conditional jump or move depends on uninitialised value(s)
==== at 0x4E80C6B: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
==== Conditional jump or move depends on uninitialised value(s)
==== at 0x4E80CEE: vfprintf (in /usr/lib64/libc-2.17.so)
==== by 0x4E893E8: printf (in /usr/lib64/libc-2.17.so)
==== by 0x4005A8: main (in /root/memcheck/malloc)
====
i =
====
==== HEAP SUMMARY:
==== in use at exit: bytes in blocks
==== total heap usage: allocs, frees, bytes allocated
====
==== LEAK SUMMARY:
==== definitely lost: bytes in blocks
==== indirectly lost: bytes in blocks
==== possibly lost: bytes in blocks
==== still reachable: bytes in blocks
==== suppressed: bytes in blocks
==== Rerun with --leak-check=full to see details of leaked memory
====
==== For counts of detected and suppressed errors,rerun with: -v
==== Use --track-origins=yes to see where uninitialised values come from
==== ERROR SUMMARY: errors from contexts (suppressed: from )

Callgrind

  和gprof 类似的分析工具,但它对程序的运行观察更细致入微,能给我们提供更多的信息。和gprof不同,它不需要在编译源代码时添加附加特殊选项,但加上调试选项是推荐的。
  Callgrind收集程序运行时的一些数据,建立函数调用关系图,还可以有选择的进行cache模拟。在运行结束时,它会把分析数据写入一个文件,callgrind_annotate可以把这个文件的内容转化成可读的形式。

  Callgrind可以帮助我们对程序的运行进行观察。

# valgrind --tool=callgrind ./malloc

  

  可以看到生成了一个文件callgrind.out.34755,同样34755为程序运行时的进程号。当callgrind运行你的程序时,还可以使用callgrind_control来观察程序的执行,而且不会干扰它的运行。
  显示程序的详细信息:

# callgrind_annotate callgrind.out.

  

Cachegrind

  Cache分析器,它模拟CPU中的一级缓存I1,DI和二级缓存,能够精确的指出程序中cache的丢失和命中。如果需要,它还能为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块整个程序产生的指令数,这对优化程序有很大的帮助。  

# valgrind --tool=cachegrind ./mallo

Helgrind

  用来检测多线程程序中出现的竞争问题。Helgrind寻找内存中内对个线程访问,而又没有一贯加锁的区域。这些区域往往是线程之间失去同步的情况,而且会导致难以发掘的错误。
  Helgrind实现了名为“Eraser”的竞争检测算法,并做了进一步改进,减少了报告错误的次数。不过Helgrinf仍然处于实验阶段。

Massif

  堆栈分析器,它能测量程序在堆栈中使用了多少内存,告诉我们堆块,堆管理块和栈的大小。Massif能帮助我们减少内存的使用,在代用虚拟内存的现代系统中,它还能加速我们程序的运行,减少程序停留在交换区中的几率。

  此外,lackey和nulgrind也会提供。Lackey是小型工具,很少用到;Nulgrind只是为开发者展示如何创建一个工具。

参考

  Linux下几款C++程序中的内存泄露检查工具
    https://blog.csdn.net/gatieme/article/details/51959654
  Linux下检测内存泄露的工具 valgrind
    https://cloud.tencent.com/developer/article/1075945
  Valgrind调试
    http://www.voidcn.com/article/p-xyrqgaum-yq.html

内存泄露检测工具Valgrind的更多相关文章

  1. linux下内存泄露检测工具Valgrind介绍

    目前在linux开发一个分析实时路况的应用程序,在联合测试中发现程序存在内存泄露的情况. 这下着急了,马上就要上线了,还好发现了一款Valgrind工具,完美的解决了内存泄露的问题. 推荐大家可以使用 ...

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

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

  3. vld(Visual Leak Detector) 内存泄露检测工具

    初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复 杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题.内存 ...

  4. 【YFMemoryLeakDetector】人人都能理解的 iOS 内存泄露检测工具类

    背景 即使到今天,iOS 应用的内存泄露检测,仍然是一个很重要的主题.我在一年前,项目中随手写过一个简单的工具类,当时的确解决了大问题.视图和控制器相关的内存泄露,几乎都不存在了.后来想着一直就那个工 ...

  5. 精准 iOS 内存泄露检测工具

    MLeaksFinder:精准 iOS 内存泄露检测工具 发表于 2016-02-22   |   zepo   |   23 Comments 背景 平常我们都会用 Instrument 的 Lea ...

  6. memwatch内存泄露检测工具

    工具介绍 官网 http://www.linkdata.se/sourcecode/memwatch/ 其功能如下官网介绍,挑选重点整理: 1. 号称功能: 内存泄露检测 (检测未释放内存, 即 动态 ...

  7. C/C++的内存泄漏检测工具Valgrind memcheck的使用经历

    Linux下的Valgrind真是利器啊(不知道Valgrind的请自觉查看参考文献(1)(2)),帮我找出了不少C++中的内存管理错误,前一阵子还在纠结为什么VS 2013下运行良好的程序到了Lin ...

  8. Android内存泄露---检测工具篇

    内存使用是程序开发无法回避的一个问题.如果我们毫不在意肆意使用,总有一天会为此还账,且痛不欲生...所以应当防患于未然,把内存使用细化到平时的每一行代码中. 内存使用概念较大,本篇先讲对已有app如何 ...

  9. Unix下C程序内存泄露检测工具:valgrind的安装使用

    Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Goo ...

随机推荐

  1. Java连载14-补码简介&浮点型整数

    一.补码简介 1.计算机中的符号数有三种表示方式,即为:原码.反码.补码.三种表示方法均有符号位和数值位,符号位都是0表示正数,符号位都是1表示负数. 2.计算机中的数字的存储方式:在计算机系统中,数 ...

  2. JS中map()与forEach()的区别和用法

    相同点: 1.都是循环遍历数组中的每一项 2.每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组) 3.匿名函数中的this都是指向window 4 ...

  3. 从原理层面掌握@ModelAttribute的使用(使用篇)【一起学Spring MVC】

    每篇一句 每个人都应该想清楚这个问题:你是祖师爷赏饭吃的,还是靠老天爷赏饭吃的 前言 上篇文章 描绘了@ModelAttribute的核心原理,这篇聚焦在场景使用上,演示@ModelAttribute ...

  4. Go-TCP粘包

    TCP黏包 黏包示例 服务端代码如下: // socket_stick/server/main.go func process(conn net.Conn) { defer conn.Close() ...

  5. 在Android Studio配置google protobuf

    1.在project的build.gradle中配置 buildscript { repositories { jcenter() mavenCentral() } dependencies { cl ...

  6. ansible模块介绍之ios_command

    一.模块简介 ios_command此模块将任意命令发送到ios节点并返回设备读取的结果 此模块不支持在配置模式下使用,即只支持在用户模式>和特权模式#下使用 官方文档地址:https://do ...

  7. 基于mybatisPlus的特殊字符校验

    要实现以下代码前提是导入Mybatis-plus的jar: * @author WENGKAIBO505 */ @Target({ElementType.FIELD, ElementType.METH ...

  8. 调度系统Airflow1.10.4调研与介绍和docker安装

    Airflow1.10.4介绍与安装 现在是9102年,8月中旬.airflow当前版本是1.10.4. 随着公司调度任务增大,原有的,基于crontab和mysql的任务调度方案已经不太合适了,需要 ...

  9. 记录一则AIX使用裸设备安装OracleRAC的问题

    需求背景:在AIX6.1上安装Oracle 10g RAC,一线工程师反馈节点2运行root脚本无法成功,跟进排查发现实际上底层存储磁盘的准备工作就存在问题. 客户要求底层存储选用裸设备方式,所以必须 ...

  10. Codeforces 1004E

    题意略. 思路: 这k个点应该放在这棵树的直径上,并且能连成一条路径.如果k比树的直径上的点要多,那么我们就不用把这k个点都用上, 只需要把这棵树直径上所有的点都覆盖上就行了.如果k比树的直径上的点要 ...