当前位置:C++技术网 > 资讯 > 资源泄露和内存泄露全面了解

资源泄露和内存泄露全面了解

更新时间:2015-06-25 22:06:03浏览次数:1+次

    什么是资源?可以说,句柄、对象、文件,内存等都是资源。而这些资源都是存在于内存中的,所以资源泄露都可以叫做是内存泄露。还有一种特指的内存泄露,就是使用动态分配得到一个内存块,但是使用完后,忘记释放了,这就是单纯的内存泄露,狭义的内存泄露。最后不管是资源泄露还是内存泄露,都可以归结为内存泄露。
    那么,什么是泄露?难道是你用的内存跑到其他进程空间去了吗?泄露的内存,实际上还是归属于你的进程,并没有到其他地方去。其实泄露,可以更准确的描述为“丢失”。就像你的手机丢在你的房间里,手机关机了,你无法找到它。内存泄露其实就是这样的一个道理。
    操作系统规定,进程申请的内存,只要没释放,且进程没有终止,那么这个内存就是属于进程的,这块内存就不能被其他进程使用。而如果你的进程申请内存后,使用完后,忘记释放,然后又重新申请,这样之前的内存就没有任何指针指向,也就无法操作了。这样对于你的进程来说,这个内存就丢了。虽然是属于你的,你却找不到。别人的进程也无法得到它。如果你重复的申请,一般是在循环中,就会导致申请大量的内存,却始终不释放。如果在循环中大量出现内存泄露,那进程很快会获取超过一定量的内存,导致系统总共可用内存就不断的减少,最后导致整个系统都变得很卡。这是比较容易发现的。但是有时候,编程习惯不好,使用了就忘记释放,一次申请的虽然不多,不释放好像没有什么关系,但是,如果是服务器程序,那一定是长时间运行,这样就导致时间久了,程序泄露的内存越来越多,最后就导致系统很卡。
    虽然程序使用的内存会泄露,但是无论如何,这些内存都是与进程相关的。这些内存都与进程关联的,操纵系统会记录的。一旦进程终止,那么这些泄露的内存都会随着系统回收进程的资源一并回收,也就恢复了正常。所以,进程泄露内存,只是发生在进程运行期间的。
    内存有两种方式,一个是堆,一个是栈。那么内存泄露会发生在堆还是栈,还是两者都可能发生呢?
    栈就是每个线程中的栈,栈用于传递参数,用保存自动变量。自动变量就是栈自动管理的,超出变量的作用域,这些变量所占的内存就会被释放。为什么呢?线程栈是一个先入后出的结构,程序中的函数调用,就会将函数中的局部变量和参数都压入栈中,这样可以很方便的传递参数,当函数执行完毕,即返回调用函数,那么之前压栈的变量参数等都要一一出栈,而出栈这个变量就失效了。而所谓的自动变量的作用域,其实就是起始于压栈,终止于出栈。而这一过程,都是由于栈的特性而成的,因为自动变量会随着这个过程自动被释放了(当然,底层会支持此时释放内存,只是这个过程很自然可以去释放)。因此,栈中使用的内存,是不会出现泄漏的。而堆是系统给所有进程预留的一块内存,进程需要栈额外的内存,就要去堆中申请。因为堆是大家共用的,如果你申请后,使用完了又去申请,把之前申请的丢了,结果要不断的申请,这样就导致堆中可用的内存越来越小,最后小到大家都不能正常使用了,程序就要崩溃(加入程序一定要堆内存才能正常运行)。而内存泄露则是因为程序员编程习惯不好,申请使用完后没有释放的好习惯。内存泄露发生在需要向堆中申请内存。其实,这个说法并不准确。
    我们再深入的想想,为什么堆会出现这个问题呢?内存泄露的本质是什么呢?假如系统给每个进程限定最大使用堆内存的大小,是不是就不会影响到其他进程了。当然是的。如果给每个进程限定了栈大小,那么一个进程因为编写的不好,导致大量的内存泄露,很快它能用的堆就用完,就不能再用了。再申请就会失败,最终进程得不到内存而崩溃。这个只影响到导致内存泄露的进程自己,不会影响到其他进程。这个看似很好,其实有问题的。系统不能限定每个进程的内存大小的。因为每个进程需要的堆的大小不确定的,如果限定,那么进程很多事情就做不了了。所以系统不能限定进程的使用的堆大小。至少这样不太合理。所以这个需要程序员来保证了。不过进程再怎么泄露内存,是不会危及系统本身的。
    这是Windows系统机制的结果。假如系统有个好的垃圾回收机制,那这个也不是问题,系统自动回收垃圾内存,这样也不用程序员来管理了。