-
内存泄漏 编辑
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
内存泄漏缺陷具有隐蔽性、积累性的特征,比其他内存非法访问错误更难检测。因为内存泄漏的产生原因是内存块未被释放,属于遗漏型缺陷而不是过错型缺陷。此外,内存泄漏通常不会直接产生可观察的错误症状,而是逐渐积累,降低系统整体性能,极端的情况下可能使系统崩溃。
随着计算机应用需求的日益增加,应用程序的设计与开发也相应的日趋复杂,开发人员在程序实现的过程中处理的变量也大量增加,如何有效进行内存分配和释放,防止内存泄漏的问题变得越来越突出。例如服务器应用软件,需要长时间的运行,不断的处理由客户端发来的请求,如果没有有效的内存管理,每处理一次请求信息就有一定的内存泄漏。这样不仅影响到服务器的性能,还可能造成整个系统的崩溃。因此,内存管理成为软件设计开发人员在设计中考虑的主要方面 。
程序存储区
静态存储区
动态存储区
程序中所用的数据分别存放在静态存储区和动态存储区中。静态存储区数据在程序的开始就分配好内存区,在整个程序执行过程中它们所占的存储单元是固定的,在程序结束时就释放,因此静态存储区数据一般为全局变量。动态存储区数据则是在程序执行过程中根据需要动态分配和动态释放的存储单元,动态存储区数据有三类函数形参变量、局部变量和函数调用时的现场保护与返回地址。由于动态存储变量可以根据函数调用的需要,动态地分配和释放存储空间,大大提高了内存的使用效率,使得动态存储变量在程序中被广泛使用。
开发人员进行程序开发的过程使用动态存储变量时,不可避免地面对内存管理的问题。程序中动态分配的存储空间,在程序执行完毕后需要进行释放。没有释放动态分配的存储空间而造成内存泄漏,是使用动态存储变量的主要问题。一般情况下,开发人员使用系统提供的内存管理基本函数,如malloc、realloc、calloc、free等,完成动态存储变量存储空间的分配和释放。但是,当开发程序中使用动态存储变量较多和频繁使用函数调用时,就会经常发生内存管理错误,例如:
分配一个内存块并使用其中未经初始化的内容;
释放一个内存块,但继续引用其中的内容;
子函数中分配的内存空间在主函数出现异常中断时、或主函数对子函数返回的信息使用结束时,没有对分配的内存进行释放;
程序实现过程中分配的临时内存在程序结束时,没有释放临时内存。内存错误一般是不可再现的,开发人员不易在程序调试和测试阶段发现,即使花费了很多精力和时间,也无法彻底消除。
产生方式的分类
以产生的方式来分类,内存泄漏可以分为四类:
常发性内存泄漏:发生内存泄漏的代码会被多次执行到,每次被执行时都会导致一块内存泄漏。
偶发性内存泄漏:发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
一次性内存泄漏:发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
隐式内存泄漏:程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
静态分析技术
静态分析技术就是直接分析程序的源代码或机器代码,获得一些有用的信息,而并不运行程序本身。目前有许多静态分析的工具,编译器就属于这一类,它读入源程序代码,对源程序进行词法和语法分析,进行数据类型的检查以及一些优化的分析等,以此来提高程序的质量与运行效率。这类静态的分析工具仅仅是读入程序代码进行相关的分析,而并不进行其它额外的操作,如修改源程序代码等。
LCLink是一种通过对源代码及添加到源代码中特定格式的注释说明进行静态分析的程序理解和检错工具,的检查对象是源程序,能检查出的内存错误有内存分配释放故障、空指针的错误使用、使用未定义或已被释放的内存等程序错误。
LCLink重点分析两类内存释放错误:
试图释放某内存块,该内存块有两个或两个以上的有效指针指向它。
试图释放某内存块,该内存块没有任何有效指针指向它。
解决此类内存错误的方法是规定分配某块内存时返回的指针必须释放该内存。使用注释表示某指针是唯一指向某内存块的指针,使用注释表示被调用函数可能释放函数参数指向的内存块或创建新的指针指向该内存块。
源代码插装技术
图1
基于源代码插装的动态测试框架分为个主要的阶段:
插装交互与动态测试信息分析;
插装阶段;
插装库制作阶段;
测试实施阶段。
插装交互与动态测试信息分析是软件测试工具与用户交互的界面。用户通过该界面选择要进行动态测试的程序模块,拓扑产生相应的插装选择记录文件。用户还可以通过该交互界而浏览动态测试结果信息,在软件测试工具的实现上,采用可视化的方式显示这些动态信息。插装阶段实现了在被测程序中植入探针,并生成带有插装信息的源文件。在此过程中,首先将被测程序经过预处理展开为不包含宏、条件编译和头文件的文件格式。然后,按照一定的插装策略,根据前面生成的插装选择记录文件,将探针函数加载到该文件中,最后生成插装后的程序。插装库制作阶段的目的是生成插装库中的探针函数,它含有插装语句调用的函数及其函数的定义。显然,插装过程中生成的目标文件中含有探针函数的桩,而探针函数的实现恰恰在本过程完成。需要指出的是,插装库的制作过程是独立于动态测试过程之外的,可以与软件测试工具开发同步。测试实施阶段将插装过程生成的文件与插装库制作过程生成的插装静态库连接生成带有插装信息的可执行文件,选取测试用例,运行该程序,可以获得被测程序的动态跟踪信息。
在以上四个阶段中,其中的插装交互与动态测试信息分析与测试实施阶段是测试人员的可视部分,通过这两部分,用户与系统交互,完成测试工作。而插装阶段与插装库制作阶段对测试人员是不可见的,在后台完成,对于用户而言,这两部分是完全透明的。在性能方面,采用插装方法应尽量减少插装开销。为了达到不同的统计目的如语句覆盖、分支覆盖等,应尽量减少插装次数。若能仅仅插装一次就能完成多种类型的统计,则可使插装代码得到优化。此外,应尽量减少插装代码的数量,减少插装代码的运行次数,从而达到减小插装代码运行开销的目的。特别是对于一些实时系统的测试,在这方面的要求尤为苛刻。一个运行时错误检测工具,能够自动检测一应用中大量的编程和运行时错误。通过使用源码插装和运行时指针跟踪的专利技术,在编译时,附十插入测试和分析代码,它建立一个有关程序中各种对象的数据库。然后在运行时通过检查数据值和内存引用验证对象的一致性和正确性。使用这些技术,包括变异测试技术等,一能够检查和测试用户的代码,精确定位错误的准确位置并给出详细的诊断信息。能够可视化实时内存操作,优化内存算法。还能执行覆盖性分析,清楚地指示那些代码已经测试过。将集成到开发环境中,能够极大地减少调试时间并有效地防止错误。检验每一次内存操作的有效性,包括静态全局和堆栈以及动态分配内存的操作。叶有两种运行模式。监护模式下用户可以快速检测代码中的错误,不需要对代码作任何插装和处理源码插装模式则进行彻底地代码检测。
目标代码插装技术
图2
被测代码预处理
图3
测试执行阶段
图4
数据统计与结果汇总
图5
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.ParasoftInsure++-针对C/C++应用的运行时错误自动检测工具,它能够自动监测C/C++程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为MicrosoftVisual 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、执行绪和内存的剖析组合在一个强大的应用中。
16.BEAJRockit-用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能。
1、本站所有文本、信息、视频文件等,仅代表本站观点或作者本人观点,请网友谨慎参考使用。
2、本站信息均为作者提供和网友推荐收集整理而来,仅供学习和研究使用。
3、对任何由于使用本站内容而引起的诉讼、纠纷,本站不承担任何责任。
4、如有侵犯你版权的,请来信(邮箱:baike52199@gmail.com)指出,核实后,本站将立即删除。