手机内存检测.ppt
1内存泄漏检测2主要内容内存泄漏定义内存泄漏原因分析内存泄漏检测方法内存泄漏检测工具内存泄漏的防范讨论3内存泄漏的定义程序中的内存结构p程序中内存分为堆、栈、全局/静态存储区和常量存储区.p全局常量位于常量存储区.p全局变量位于静态数据区.p局部变量以及函数参数变量位于栈.p使用new/malloc分配的内存位于堆上.栈 代码区静态数据区高端内存区域 常量存储区堆低端内存区域常量存储区域和静态数据区域的内存在程序退出时释放栈中分配的内存在变量离开其作用域时释放堆中分配的内存必须显示的释放4内存泄漏的定义内存泄漏的定义p程序中从堆中分配的内存在使用完毕后忘记释放,从而失去对该块内存的控制,导致该块内存一直被占用直至程序退出。程序一直分配内存,直到程序退出才释放所有内存。内存泄漏的危害p程序占用内存越来越多,使得整个系统运行速度越来越慢。糟糕者可用内存耗尽,应用程序崩溃。5内存泄漏的定义内存泄漏的分类p常发性内存泄漏发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。p一次性内存泄漏发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。p偶发性内存泄漏发生内存泄漏的代码只会被执行一次p隐式内存泄漏程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存6内存泄漏原因分析new出来的对象没有deletep代码中没有delete的地方p指针被重新赋值了,赋值前没有deletep逻辑分支考虑不全。函数内部逻辑考虑不周。接口调用时序逻辑考虑不全CUDPSocket*CreateUdpSocket(const std:string&sIpAdress,UINT nLocalAudioPort)CUDPSocket*pUdpSocket=new CUDPSocket();CInetAddress oInetAddress(sIpAddress);SOCKERROR err=pUdpSocket-Create(&oInetAddress,nLocalAudioPort);if(SOCKET_SUCCESS!=err)/delete pUdpSocket;/pUdpSocket=0;return NULL;return pUdpSocket;内存泄漏原因分析基类析构函数非虚p当基类指针指向派生类对象,delete该基类指针时派生类对象的析构不会被调用。如果派生类中使用了stl容器或者从堆中分配内存的作为成员变量,那么内存泄漏就悄无声息的发生了。7class CIavpMsgpublic:CIavpMsg()CIavpMsg()printf(CIavpMsg()rn);class CLogMsg:public CIavpMsgpublic:CLogMsg()CLogMsg()printf(CLogMsg()rn);public:string m_sTime;int _tmain(int argc,_TCHAR*argv)CIavpMsg*pMsg=new CLogMsg();string&sTime=(CLogMsg*)pMsg)-m_sTime;int nCapacity=sTime.capacity();printf(sTime初始内存大小:%drn,nCapacity);sTime=2010年月日:18:01;nCapacity=sTime.capacity();printf(sTime赋值内存大小:%drn,nCapacity);const char*pStr=sTime.c_str();delete pMsg;printf(LogMsg对象删除后m_sTime的内容:%srn,pStr);return 0;内存泄漏原因分析8内存泄漏原因分析delete一个只有声明没有定义的类p 为了避免C/C+头文件中包含很多的其他头文件,通常将关联到的其他类型声明一下即可,在真正使用的地方包含其类定义的头文件。p如果在某个地方delete一个只有声明,而没有包含其类定义的头文件,那么该delete将不会去调用该类的析构函数。其结果和基类析构非虚导致派生类的析构不被调用的后果一样。9#pragma onceclass CIavpMsg;class CIavpMsgFactorypublic:/从网络收到的消息创建成一个IavpMsg CIavpMsg*DynamicCreateMsg(const char*pMsgStream,int nStreamLen);#include stdafx.h#include iavpmsgfactory.hint _tmain(int argc,_TCHAR*argv)CIavpMsgFactory oMsgFactory;CIavpMsg*pMsg=oMsgFactory.DynamicCreateMsg(0,0);/DoSomeThingWithIavpMsg(pMsg);delete pMsg;return 0;内存泄漏原因分析向容器中不断的添加内容,而不删除内容。p 写代码时疏忽,逻辑判断不正确导致此种情况发生。p接口设计不良,容器删除的职责不明。10内存泄漏原因分析11class CTTSPlayerpublic:TTSPlayTaskID PrepareTask(const char*ttstext,TtsPlayResultHandler&handler,void*param,const PlayEndPoint&endPoint)CTTSPlayerThread*pPlayerThread=new CTTSPlayerThread();m_oTTSPlayerMapm_nID+=pPlayerThread;return m_nID;void Play(TTSPlayTaskID taskID)/1.从容器中找到playthread/2.异步调用playthread的play接口 void Stop(TTSPlayTaskID taskID)/1.从容器中找到playthread/2.delete playthread/3.从容器中删除playthread private:std:map m_oTTSPlayerMap;TTSPlayTaskID m_nID;Play失败,异步通知给调用者,调用者认为Play已经失败,没有必要再去调用Stop接口了,map容器中保存的对象永远不会被删除了,直至程序退出,从而导致内存泄漏!内存泄漏原因分析指针所有权不明p函数返回一个指针,却没说明该谁释放。12class CRtspClientpublic:/其他方法声明 /向RTSP服务器发送Option消息,返回服务器的响应结果 char*SendOption();private:/成员变量声明 ;返回值要不要delete?内存泄漏原因分析SDK或第三方库使用不当pFormatMessage方法指定FORMAT_MESSAGE_ALLOCATE_BUFFER则该方法得到的字符串为系统分配,需要LocalFree释放该字符串。13int _tmain (int argc,_TCHAR*argv)TCHAR*buffer=new TCHAR100;TCHAR*pClone=buffer;ZeroMemory(pClone,100);TCHAR*s=orig orig orig orig;memcpy(pClone,s,strlen(s);DWORD error=ERROR_STACK_OVERFLOW;DWORD dwRet=:FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,NULL,error,0,(LPTSTR)&buffer,0,NULL);printf(%srn,buffer);printf(%srn,pClone);/LocalFree(buffer);return 0;内存泄漏检测方法代码检查p所有的new有没有对应的delete?p基类的析构是否是虚函数?p代码逻辑是否存在漏洞?p调用第三方库接口或者SDK的方法是否正确合理?p仔细阅读编译结果,不要忽视warning.14 warning C4150:删除指向不完整“CIavpMsg”类型的指针;没有调用析构函数Warning:代码检查需仔细,每一行都要认真推敲,切忌走马观花!内存泄漏检测方法单元测试p第三方提供的库只有接口,没有源码。p通过代码检查发现了可疑泄漏模块,对该模块写一个简单单元测试程序,进行压力测试,通过观察内存占用曲线,确定该模块是否存在泄漏。15成功案例:成功案例:iAvp2.4开发中对nuance的opencalllog和closecallog的接口进行单元测试,发现nuance此处存在泄漏。内存泄漏检测方法使用内存泄漏检测工具 在Windows平台下,内存泄漏检测工具一般有三种。p内存实时监控,如iAvp的showin工具;pMS C-Runtime Library内建的检测功能;p外挂式的检测工具,诸如Purify,BoundsChecker等;16内存泄漏检测工具内存实时监控,如iAvp的showin工具p 定时检测内存占用情况,绘制成内存占用曲线。p 根据曲线的斜率,显示内存泄漏严重程度。p 无法定位内存泄漏的代码。17内存泄漏检测工具MS C-Runtime Library内建的检测功能p 使用MS C-Runtime Library调试堆函数。181.要使用crt的调试堆函数,首先在程序添加如下语句:2.程序退出的地方调用_CrtDumpMemoryLeaks:_CrtDumpMemoryLeaks();#define _CRTDBG_MAP_ALLOC#include#include 语句顺序不可改变3.程序有多个出口时无需在每个出口调用_CrtDumpMemoryLeaks,程序的开始处调用_CrtSetDbgFlag 即可:_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF);内存泄漏检测工具MS C-Runtime Library内建的检测功能p 内存泄漏报告输出191._CrtDumpMemoryLeaks报告默认输出到VS调试输出窗口。问题1:必须在VS IDE上以调试的方式运行,对于需要进行压力测试的程序非常不方便。问题2:在IDE的调试输出窗口分析泄漏报告很不方便。2.改变内存泄漏报告的输出位置。freopen(sDumpFile,w,stderr);_CrtSetReportMode(_CRT_WARN,_CRTDBG_MODE_FILE);_CrtSetReportFile(_CRT_WARN,_CRTDBG_FILE_STDERR);_CrtDumpMemoryLeaks();fclose(stderr);内存泄漏检测工具MS C-Runtime Library内建的检测功能p 内存泄漏报告分析201.应用程序没有定义_CRTDBG_MAP_ALLOC,报告输出如下:Detected memory leaks!Dumping objects-18 normal block at 0 x00780E80,64 bytes long.Data:CD CD CD CD CD CD CD CD CD CDObject dump complete.Detected memory leaks!Dumping objects-C:leaktestleaktest.cpp(20):18 normal block at 0 x00780E80,64 bytes long.Data:CD CD CD CD CD CD CD CD CD CD CD CDObject dump complete.2.应用程序定义了_CRTDBG_MAP_ALLOC,报告输出如下:_CRTDBG_MAP_ALLOC可以在报告中显示泄漏在文件中发生的位置内存泄漏检测工具MS C-Runtime Library内建的检测功能p 内存泄漏报告分析21Detected memory leaks!Dumping objects-C:leaktestleaktest.cpp(20):18 normal block at 0 x00780E80,64 bytes long.Data:CD CD CD CD CD CD CD CD CD CD CD CDObject dump complete.泄漏内存的分配号泄漏内块的类型泄漏内存的地址泄漏内存的大小泄漏内存前16字节的内容泄漏内存发生的位置内存泄漏检测工具22MS C-Runtime Library内建的检测功能p C+使用crt调试堆函数,需要添加如下代码#ifdef _DEBUG#ifndef DBG_NEW#define DBG_NEW new(_NORMAL_BLOCK,_FILE_,_LINE_)#define new DBG_NEW#endif#endif 注意:不要将上述代码添加在stl库的头文件前面,否则编译不通过!内存泄漏检测工具IBM Rational Purifyp使用Object Code Insertion技术,无需修改源代码,只需目标程序及其调试符合PDB文件即可。pPurify工作流程23内存泄漏检测工具IBM Rational PurifypPurify的使用 241.加载程序内存泄漏检测工具252.分析报告内存泄漏检测工具IBM Rational Purifyp 不足之处261.跑大型复杂程序比较费劲,对服务器环境要求较高,有时程序无法启动1.不是免费的,破解版稳定性较差内存泄漏检测工具其他内存泄露工具简介pParasoft Insure+针对C/C+应用的运行时错误自动检测工具,它能够自动监测C/C+程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为Microsoft Visual C+的一个插件运行。pBoundsChecker 类似于Insure+,都是以插件方式运行,程序的运行必须在IDE环境上运行。p.27总结1:通过多个项目实践经验表明,使用C-Runtime Library 堆调试最为方便和有效!总结2:内存泄漏查找的是一件复杂的工作,需要开发团队和测试团队有效沟通,共同努力!总结3:不要依赖工具,最好的排除方法是不让内存泄漏的情况发生!内存泄漏防范内存泄露防范几点建议28建议1:少使用new,除非必须使用。建议2:使用智能指针。建议3:如果一个接口的实现中有分配内存动作,必须有一个对应的释放接口。建议4:复杂逻辑的代码段最好使用结对编程。建议5:版本构建前,使用C-Runtime Library堆调试加强单元测试。2929讨论你有什么更好的你有什么更好的经验,说出来大家一起分享下!出来大家一起分享下!