您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 其它文档 > 软件编程低级错误:内存泄漏
HUAWEITECHNOLOGIESCO.,LTD.HuaweiConfidentialSecurityLevel:InternalPublic语言软件编程规范工作组公司常见软件编程低级错误:内存泄漏Page2HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.前言•这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。•C和C++语言是我司的主流编程语言,然而C/C++具有很多强大的语言特性,从而导致C/C++非常复杂,使得代码更容易出现BUG、难以阅读和维护。•业界知名的编程规范都对C/C++容易出现问题的语言特性进行管理。例如MISRA(汽车工业软件可靠性联合会)制定的1998版的MISRAC规范指出,一些在C看来可以接受,却存在隐患的地方有127处之多。2004版的MISRAC规范将针对C语言的规则增加到了141条。•对于程序员来说,能工作的代码并不等于“好”代码。“好”代码的指标很多,包括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数是不良编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。•本胶片收集了常见的内存泄漏案例,给出了相应的纠正措施。对应的编程规范:防止内存泄漏;函数中分配的内存,在函数退出之前要释放Page3HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.内存泄漏案例问题和纠正措施建议Page4HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.异常出口处没有释放内存【问题描述】代码飞检发现如下代码:pMsgDB_DEV=(PDBDevMsg)GetBuff(sizeof(DBDevMsg),__LINE__);if(pMsgDB_DEV==NULL){return;}pMsgDBApp_To_Logic=(LPDBSelfMsg)GetBuff(sizeof(DBSelfMsg),__LINE__);if(pMsgDBApp_To_Logic==NULL){return;}【问题定位】在第2个return处,pMsgDB_DEV指向的内存丢失Page5HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.异常出口处没有释放内存(续1)【问题描述】代码飞检发现如下代码:/*在AVL树中添加节点*/IF_VC_AVL_AddNode(&stAVLNodeKey,pstBasPortIndex,IF_VC_AVL_CompareNode)ulRet=IF_BAS_VC_CreateVC((*pstBasPortIndex),ulIfIndex);if(ulRet!=VOS_OK)/*创建VC控制块失败*/{return;}【问题定位】创建VC控制块失败时,return前没有删除AVL树中的节点【举一反三】看见return要注意,要去前面找资源,特别要注意链表等数据结构中的资源Page6HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.异常出口处没有释放信号量资源【问题描述&定位】代码飞检发现如下代码:rc=np_ss_semB_create(NP_SEM_EMPTY,NP_SEM_Q_FIFO,(g_ims_vport_base_info.qinq_base_info.sem));if(rc!=NP_RC_SUCCESS)/*申请信号量失败*/{NP_SS_ASSERT(0,Createqinqsemfailed!);returnrc;}#ifSOFT_Versionrc=np_ss_semB_create(NP_SEM_EMPTY,NP_SEM_Q_FIFO,&(g_ims_vport_base_info.eqinq_base_info.sem));if(rc!=NP_RC_SUCCESS)/*申请信号量失败*/{NP_SS_ASSERT(0,Createqinqsemfailed!);returnrc;//没有释放前面分配的信号量g_ims_vport_base_info.qinq_base_info.sem}#endif………………………….NP_FREE_SEM(g_ims_vport_base_info.qinq_base_info.sem);#ifSOFT_VersionNP_FREE_SEM(g_ims_vport_base_info.eqinq_base_info.sem);#endifreturnrc;Page7HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.异常出口处没有释放信号量资源(续)【纠正措施】第二个信号量申请失败return之前释放第一个申请的信号量。。。。。。。。。。。。#ifSOFT_Versionrc=np_ss_semB_create(NP_SEM_EMPTY,NP_SEM_Q_FIFO,&(g_ims_vport_base_info.eqinq_base_info.sem));if(rc!=NP_RC_SUCCESS)/*申请信号量失败*/{NP_SS_ASSERT(0,Createqinqsemfailed!);NP_FREE_SEM(g_ims_vport_base_info.qinq_base_info.sem);returnrc;}#endif。。。。。。。。。。。。【举一反三】看见return要注意,要去前面找资源,特别要注意信号量、定时器等资源Page8HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.异常出口处没有释放GUI资源【问题描述】网上问题案例:CBitmapbmp;CBitmap*pOldBmp;bmp.LoadBitmap(IDB_MYBMP);pOldBmp=pDC-SelectObject(&bmp);if(Something()){return;}pDC-SelectObject(pOldBmp);【问题定位】return前没有调用SelectObject()把pOldBmp选回pDC中,这会导致pOldBmp指向的HBITMAP对象发生泄漏。这个程序如果长时间的运行,会导致系统花屏【举一反三】除了申请的内存外,系统提供的其它资源,如文件句柄/Socket/队列等也是资源,使用完毕必须释放Page9HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.没有释放结构的成员指针【问题描述】网上问题案例:structSTORE_BUF_S{ULONGulLen;UCHAR*pcData;}STORE_BUF_T;voidfunc(){STORE_BUF_T*pstStorageBuff=NULL;//申请结构内存//程序处理。。。free(pstStorageBuff);return;}删除了pstStorageBuff,但pstStorageBuff-pcData没有删除。【问题定位】先删除了pstStorageBuff,pstStorageBuff-pcData永远不可能被删除了【举一反三】删除结构指针时,必须从底层向上层顺序删除Page10HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.没有释放数组的成员指针【问题描述】测试部对M产品进行压力和稳定性测试,模拟文件上传的场景,把本地目录下的3万个文件上传到另一台主机。发现上传程序在传送文件过程中,内存在快速增长,通过psauwx监控,发现该进程占用的内存每隔4分钟(一个周期)就突然增加20~30M的内存。【问题定位】structdirent**namelist;intn=scandir(path.c_str(),&namelist,0,alphasort);【1】inti=0;for(i;in;++i){stringname=namelist[i]-d_name;free(namelist[i]);【2】if(name!=..&&name!=.){.........++fileNum;if(MAX_SCAN_FILE_NUM==fileNum)//MAX_SCAN_FILE_NUM=1000{break;}}}free(namelist);【3】return;Page11HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.没有释放数组的成员指针(续)从上面的代码可以看是指针数组namelist由系统函数进行分配内存(如【1】所示),内存释放时时分别由【2】【3】完成的。但是中间有个条件,每次只取1000个文件,如果目录下的文件大于1000就跳出,后面的就不会再管了(【2】没有执行到)。所以导致原来本地目录下文件数比较小,小于等1000时没有内存泄漏;而当本地目录下的文件比较多,大于1000时,就会导致内存泄漏。【举一反三】开发人员在使用指针数组时,要特别注意,确保在释放数组时,数组中的每个元素指针是否已经提前被释放了,这样才不会导致内存泄漏。Page12HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.重复分配内存【问题描述】代码飞检发现如下代码:ULONGCQC_CmdNoDropLevelClass(VOID*pMsgRcv,VOID**ppMsgSnd){/*以下是从别处拷贝的代码*/ulErrCode=CFG_CreateResMsgs(pMsgRcv,ppMsgSnd));………………/*拷贝代码结束*/………………ulErrCode=CFG_CreateResMsgs(pMsgRcv,ppMsgSnd));………………}【举一反三】代码Copy要小心Page13HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.没有释放传入定时器的内存【问题描述】使用purify测试,发现上报MLK:在我们的应用程序的对象中,由于在设置定时器时需要传递一个参数,这个参数的需要从堆中去获取,因为在后续的定时器超时回调时需要使用这个参数。在对象中设置定时器的代码如下:this-setTimer(timerId,pending_user_enroll_timer_id,30,1,//设置一个30秒的定时器,定时1次newTString(ipport));在定时器的超时处理程序简化后如下:voidSession::onTimeOut(TInt4timerID,TInt4userTimerID,void*pData){switch(userTimerID){casepending_user_enroll_timer_id:{TString*ipport=reinterpret_castTString*(pData);...deleteipport;}...}}在我们设置的定时器超时后,会自动调用onTimeOut这个函数,根据userTimerID来把所需要的参数转化为我们原来的数据类型,使用完成后在销毁它。这看起来一切都很正常,new出来资源通过delete来进行释放,为什么出现了内存泄漏呢?Page14HuaweiConfidentialHUAWEITECHNOLOGIESCO.,LTD.没有释放传入定时器的内存(续)【问题定位】定时器设置之后在未超时的时候,这个定时器的所在的对象就结束了,定时器自然就消失了,也就是我们new出来的东西也就消失了,内存泄漏就此产生了。【纠正措施】使用智能指针进行解决,资源的释放操作由C++语言特性进行保证(在对象的生命周期结束调用其析构函数),具体方案如下:在该对象类添加一个智能指针类型的私有成员变量:private:std::auto_ptrTStringtimer_arg_ipport_;这样,在该对象被销毁时,根据
本文标题:软件编程低级错误:内存泄漏
链接地址:https://www.777doc.com/doc-1748448 .html