内存泄露

来源:互联网 发布:美图秀秀软件介绍 编辑:程序博客网 时间:2024/04/27 13:15


  程序退出后,malloc的内存会不会自动free呢?要回答这个问题,我们先要熟悉进程空间的内存相关结构.


一般编程主要只涉及进程的堆空间和栈空间(当然进程还有其他的,但初学可以不考虑).

栈空间的内存是给函数内的局部变量(包括函数参数)用的,通过函数调用和函数返回自动得分配释放(实际上只是调整栈顶指针的位置)。因为这是个“自动”的过程,所以有个额外的“栈空间溢出”的问题,主要的就是函数内局部变量不宜过大(比如int array[100*1024*1024],申请100M的内存),递归调用不要嵌套过多。

堆空间的内存简单的说就是通过malloc/new申请的,你可以选择在不再使用时释放(用free/delete),但不是必须这么做——程序退出时系统会自动回收该进程所占用的内存(僵尸进程有一点例外--它要保存进程的返回值,直到被取走才释放)。不释放内存只有两个害处:一是本进程达到能申请内存的最大值然后申请失败,导致本进程无法继续正常运行;二是本进程占用内存过多,影响系统的其他进程,或者是提高本程序运行的硬件要求。

下面的这个小例子,就是验证一下进程退出后会不会自动释放malloc的内存:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

void fun( int i);
int *p;
void fun( int i)
{
    p = malloc(sizeof(int));
    *= i;
    printf("malloc successful,and %d has been store to the memory!\n",i);
    printf("malloc the address is %x\n",p);
    exit (0);
}

int main(void)
{
    pid_t pid;
    int k;
    int status;
    k = fork();
    if ( k == 0)
    {
        fun(1);
    }
    else {
        sleep(1);
        printf("------\n");
        pid = wait(&status);
        printf("%x\n",p);
        printf("%d\n",*p);
        return 0;
    }
}



$ ./a.out 
malloc successful,and 1 has been store to the memory!
malloc the address is 804a008
------
0

Segmentation fault


看来进程退出后,malloc的内存也随之由系统自动释放了.

大多数情况下,程序浪费“有限”的内存是关系不大的。但如果某函数每被调用一次就浪费一点内存(即申请了内存,不再使用,却不释放),随着函数被调用次数的增多,浪费的内存趋于“无限”,就会产生严重的问题,即所谓“内存泄露”。“内存泄露”的存在有两个必要条件,一是程序在持续的“浪费”内存,二是程序没有退出。所以,如果能保证程序在正常退出前浪费的内存不超过某一阈值,就可以不考虑释放内存(这也就是我们写小测试程序的情况)。

以上是内存申请了可以不释放的情况,其他情况下(比如程序需要持久运行,这也是实际中最常见的情况),申请的内存都需要释放。下面再说什么时候要申请(malloc/new)内存:
需要申请(malloc/new)内存是出于这样一种需要:栈空间是线程相关的(即栈空间的内存属于某一固定的线程),而我们有时需要线程无关即多个线程共享的内存(换个角度说,对于单线程程序,完全可以只用栈空间完成一切任务,即不用申请内存,只需把函数退出后仍需保留的变量声明在函数外面,代价就是函数参数个数的增多)。事实上,多线程比之单进程,唯一的进步也就是方便了对线程无关内存的访问,也就是可以让堆空间像多进程编程中的共享内存一样使用。

堆空间和栈空间两者之和虽然受到32位进程4G地址空间的限制,但两者之和却可相互调整:比如线程很多时可能需要增大栈空间减小堆空间,线程共享空间需求很大时则反之。

当然,c/c++有很多内存泄漏检测工具,
内存泄漏检测工具:

1.ccmalloc-Linux和Solaris下对C和C++程序的简单的使用内存泄漏和malloc调试库。
2.Dmalloc-Debug Malloc Library.
3.Electric Fence-Linux分发版中由Bruce Perens编写的malloc()调试库。
4.Leaky-Linux下检测内存泄漏的程序。
5.LeakTracer-Linux、Solaris和HP-UX下跟踪和分析C++程序中的内存泄漏。
6.MEMWATCH-由Johan Lindh编写,是一个开放源代码C语言内存错误检测工具,主要是通过gcc的precessor来进行。
7.Valgrind-Debugging and profiling Linux programs, aiming at programs written in C and C++.
8.KCachegrind-A visualization tool for the profiling data generated by Cachegrind and Calltree.
9.IBM Rational PurifyPlus-帮助开发人员查明C/C++、托管.NET、Java和VB6代码中的性能和可靠性错误。PurifyPlus 将内存错误和泄漏检测、应用程序性能描述、代码覆盖分析等功能组合在一个单一、完整的工具包中。
10.Parasoft Insure++-针对C/C++应用的运行时错误自动检测工具,它能够自动监测C/C++程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O 等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为 Microsoft Visual C++的一个插件运行。
11.Compuware DevPartner for Visual C++ BoundsChecker Suite-为C++开发者设计的运行错误检测和调试工具软件。作为Microsoft Visual Studio和C++ 6.0的一个插件运行。
12.Electric Software GlowCode-包括内存泄漏检查,code profiler,函数调用跟踪等功能。给C++和.Net开发者提供完整的错误诊断,和运行时性能分析工具包。
13.Compuware DevPartner Java Edition-包含Java内存检测,代码覆盖率测试,代码性能测试,线程死锁,分布式应用等几大功能模块。
14.Quest JProbe-分析Java的内存泄漏。
15.ej-technologies JProfiler-一个全功能的Java剖析工具,专用于分析J2SE和J2EE应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中。 JProfiler可提供许多IDE整合和应用服务器整合用途。JProfiler直觉式的GUI让你可以找到效能瓶颈、抓出内存泄漏、并解决执行绪的问题。4.3.2注册码:A-G666#76114F-1olm9mv1i5uuly#0126
16.BEA JRockit-用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能。


比如valgrind就是在Linux下查找内存泄漏和无效内存访问.具体可以参考下文:
在Linux下使用用Valgrind查找内存泄漏和无效内存访问 http://www.linuxidc.com/Linux/2009-02/18646.htm

还有memwatch,可以参考下文
内存调试--MEMWATCH http://blog.csdn.net/lengxingfei/archive/2006/08/09/1040800.aspx 

当然,你也可以自己封装自己的malloc/free来实现内存的检测

实用小代码之内存泄漏检测  http://blog.chinaunix.net/u/18677/showart_473613.html
实用小代码之内存泄漏检测(二) http://blog.chinaunix.net/u/18677/showart_547975.html 


reference:

内存泄漏(资料搜集)http://blog.chinaunix.net/u2/78225/showart_1844866.html
啥时需要申请内存和释放内存?http://blog.chinaunix.net/u1/47120/showart_372045.html