




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、HUAWEI TECHNOLOGIES CO., LTD.Huawei Confidential Security Level: Internal PCC语言软件编程规范工作组语言软件编程规范工作组公司常见软件编程低级公司常见软件编程低级错误:内存泄漏错误:内存泄漏Page 2Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.前言这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。这套材料作为编程规范的辅助材料,帮助大家理解编程规范背后的原理。C和和C+语言是我司的主流编程语言,然而语言是我司的主流编程语言,然而C/C+具有很多强大的
2、语言特性,从而导具有很多强大的语言特性,从而导致致C/C+非常复杂,使得代码更容易出现非常复杂,使得代码更容易出现BUG、难以阅读和维护。、难以阅读和维护。业界知名的编程规范都对业界知名的编程规范都对C/C+容易出现问题的语言特性进行管理。例如容易出现问题的语言特性进行管理。例如MISRA(汽车工业软件可靠性联合会)制定的(汽车工业软件可靠性联合会)制定的1998版的版的MISRAC规范指出,一些在规范指出,一些在C看来看来可以接受,却存在隐患的地方有可以接受,却存在隐患的地方有127处之多。处之多。2004版的版的MISRAC规范将针对规范将针对C语言语言的规则增加到了的规则增加到了141条
3、。条。对于程序员来说,能工作的代码并不等于对于程序员来说,能工作的代码并不等于“好好” 代码。代码。“好好”代码的指标很多,包代码的指标很多,包括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数是不良括可读性、可维护性、可移植性和可靠性等。出现网上问题的代码,大多数是不良编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。编程习惯引起的。不遵守编程规范的代码,往往也是最不可靠的代码。本胶片收集了常见的内存泄漏案例,给出了相应的纠正措施。对应的编程规范:防本胶片收集了常见的内存泄漏案例,给出了相应的纠正措施。对应的编程规范:防止内存泄漏;函数中分配的内存,在函数退出之前
4、要释放止内存泄漏;函数中分配的内存,在函数退出之前要释放Page 3Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.内存泄漏案例问题和纠正措施建议Page 4Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.异常出口处没有释放内存【问题描述问题描述】代码飞检发现如下代码:pMsgDB_DEV = (PDBDevMsg)GetBuff( sizeof( DBDevMsg ), _LINE_);pMsgDB_DEV = (PDBDevMsg)GetBuff( sizeof( DBDevMsg ), _
5、LINE_);if( pMsgDB_DEV = NULL ) return;pMsgDBApp_To_Logic = (LPDBSelfMsg)GetBuff( sizeof(DBSelfMsg), _LINE_ );if( pMsgDBApp_To_Logic = NULL ) return;return;【问题定位问题定位】在第2个return处,pMsgDB_DEV指向的内存丢失Page 5Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.异常出口处没有释放内存(续1)【问题描述问题描述】代码飞检发现如下代码:/* 在AVL树中添加节点 *
6、/IF_VC_AVL_AddNode( &stAVLNodeKey, pstBasPortIndex, IF_VC_AVL_CompareNode)ulRet = IF_BAS_VC_CreateVC(*pstBasPortIndex),ulIfIndex);if (ulRet != VOS_OK ) /* 创建VC控制块失败 */ return;return;【问题定位问题定位】创建VC控制块失败时,return前没有删除AVL树中的节点【举一反三举一反三】看见return要注意,要去前面找资源,特别要注意链表等数据结构中的资源Page 6Huawei Confidential HU
7、AWEI TECHNOLOGIES CO., 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, Create qinq sem failed!); return rc; #if SOFT_Versionrc = np_ss_
8、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, Create qinq sem failed!); return rc; /没有释放前面分配的信号量没有释放前面分配的信号量g_ims_vport_base_info.qinq_base_info.sem #endif .NP_FREE_SEM(g_ims_vport_base_info.qinq_ba
9、se_info.sem); #if SOFT_VersionNP_FREE_SEM(g_ims_vport_base_info.eqinq_base_info.sem); #endif return rc;Page 7Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.异常出口处没有释放信号量资源(续)【纠正措施纠正措施】第二个信号量申请失败第二个信号量申请失败return之前释放第一个申请的信号量之前释放第一个申请的信号量。#if SOFT_Versionrc = np_ss_semB_create(NP_SEM_EMPTY, NP_SEM_Q_
10、FIFO, &(g_ims_vport_base_info.eqinq_base_info.sem);if(rc != NP_RC_SUCCESS)/*申请信号量失败申请信号量失败*/ NP_SS_ASSERT(0, Create qinq sem failed!); NP_FREE_SEM(g_ims_vport_base_info.qinq_base_info.sem); return rc; #endif。【举一反三举一反三】看见看见return要注意,要去前面找资源,特别要注意信号量、定时器等资源要注意,要去前面找资源,特别要注意信号量、定时器等资源Page 8Huawei C
11、onfidential HUAWEI TECHNOLOGIES CO., 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对象发生泄漏。这个程序如果长时间的运行,会导
12、致系统花屏【举一反三举一反三】除了申请的内存外,系统提供的其它资源,如文件句柄/Socket/队列等也是资源,使用完毕必须释放Page 9Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放结构的成员指针【问题描述问题描述】网上问题案例:网上问题案例:struct STORE_BUF_S ULONG ulLen; UCHAR *pcData;STORE_BUF_T;void func() STORE_BUF_T *pstStorageBuff = NULL; /申请结构内存申请结构内存 /程序处理。程序处理。 free(pstStorage
13、Buff); return;删除了删除了pstStorageBuff,但,但pstStorageBuff-pcData没有删除。没有删除。【问题定位问题定位】先删除了先删除了pstStorageBuff,pstStorageBuff-pcData永远不可能被删除了永远不可能被删除了 【举一反三举一反三】删除结构指针时,必须从底层向上层顺序删除删除结构指针时,必须从底层向上层顺序删除 Page 10Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放数组的成员指针【问题描述问题描述】测试部对测试部对M产品进行压力和稳定性测试,模拟文件上传的场
14、景,把本地目录下的产品进行压力和稳定性测试,模拟文件上传的场景,把本地目录下的3万个文件上传到另一台主机。发现上传程序在传送文件万个文件上传到另一台主机。发现上传程序在传送文件过程中,内存在快速增长,通过过程中,内存在快速增长,通过ps auwx监控,发现该进程占用的内存每隔监控,发现该进程占用的内存每隔4分钟(一个周期)就突然增加分钟(一个周期)就突然增加2030M的内存。的内存。【问题定位问题定位】struct dirent *namelist; int n = scandir(path.c_str(), &namelist, 0, alphasort);【1】 int i = 0
15、; for(i ; i d_name; free(namelisti); 【2】 if(name != . & name != .) . +fileNum; if(MAX_SCAN_FILE_NUM = fileNum )/MAX_SCAN_FILE_NUM=1000 break; free(namelist); 【3】 return ;Page 11Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放数组的成员指针(续)从上面的代码可以看是指针数组从上面的代码可以看是指针数组namelist由系统函数进行分配内存(由系统函数进行分
16、配内存(如如【1】所示),内存释放时时分别由所示),内存释放时时分别由【2】【】【3】完成的。完成的。但是中间有个条件,每次只取但是中间有个条件,每次只取1000个文件,如果目录下的文件大于个文件,如果目录下的文件大于1000就跳出,后面的就不会再管了(就跳出,后面的就不会再管了(【2】没有执行到)。所以导没有执行到)。所以导致原来本地目录下文件数比较小,小于等致原来本地目录下文件数比较小,小于等1000时没有内存泄漏;时没有内存泄漏;而当本地目录下的文件比较多,大于而当本地目录下的文件比较多,大于1000时,就会导致内存泄漏时,就会导致内存泄漏。【举一反三举一反三】开发人员在使用指针数组时,
17、要特别注意,确保在释放开发人员在使用指针数组时,要特别注意,确保在释放数组时,数组中的每个元素指针是否已经提前被释放了,这样才不数组时,数组中的每个元素指针是否已经提前被释放了,这样才不会导致内存泄漏。会导致内存泄漏。Page 12Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.重复分配内存【问题描述问题描述】代码飞检发现如下代码:ULONG CQC_CmdNoDropLevelClass(VOID* pMsgRcv,VOID* ppMsgSnd)/* 以下是从别处拷贝的代码 */ulErrCode = CFG_CreateResMsgs(pM
18、sgRcv, ppMsgSnd)ulErrCode = CFG_CreateResMsgs(pMsgRcv, ppMsgSnd); ; /* 拷贝代码结束 */ulErrCode = CFG_CreateResMsgs(pMsgRcv, ppMsgSnd);ulErrCode = CFG_CreateResMsgs(pMsgRcv, ppMsgSnd); 【举一反三举一反三】 代码Copy要小心Page 13Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放传入定时器的内存【问题描述问题描述】使用使用purify测试,发现上报测试,发现上
19、报MLK:在我们的应用程序的对象中,由于在设置定时器时需要传递一个参数,这个参数的需要从堆中去获取,因为在后续的定时器超时回调时需要使用这个在我们的应用程序的对象中,由于在设置定时器时需要传递一个参数,这个参数的需要从堆中去获取,因为在后续的定时器超时回调时需要使用这个参数。在对象中设置定时器的代码如下:参数。在对象中设置定时器的代码如下:this-setTimer(timerId, pending_user_enroll_timer_id, 30, 1, / 设置一个设置一个30秒的定时器,定时秒的定时器,定时1次次new TString(ipport);在定时器的超时处理程序简化后如下:在
20、定时器的超时处理程序简化后如下:void Session:onTimeOut(TInt4 timerID, TInt4 userTimerID, void* pData)switch(userTimerID) case pending_user_enroll_timer_id: TString* ipport = reinterpret_cast(pData);.delete ipport; .在我们设置的定时器超时后,会自动调用在我们设置的定时器超时后,会自动调用onTimeOut这个函数,根据这个函数,根据userTimerID来把所需要的参数转化为我们原来的数据类型,使用完成后在销毁来把
21、所需要的参数转化为我们原来的数据类型,使用完成后在销毁它。这看起来一切都很正常,它。这看起来一切都很正常,new出来资源通过出来资源通过delete来进行释放,为什么出现了内存泄漏呢?来进行释放,为什么出现了内存泄漏呢?Page 14Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放传入定时器的内存(续)【问题定位问题定位】定时器设置之后在未超时的时候,这个定时器的所在的对象就结束了,定时器自然就消失了,也就是我们定时器设置之后在未超时的时候,这个定时器的所在的对象就结束了,定时器自然就消失了,也就是我们new出来的东西也出来的东西也就消
22、失了,内存泄漏就此产生了。就消失了,内存泄漏就此产生了。【纠正措施纠正措施】使用智能指针进行解决,资源的释放操作由使用智能指针进行解决,资源的释放操作由C+语言特性进行保证(在对象的生命周期结束调用其析构函数),具体方案如语言特性进行保证(在对象的生命周期结束调用其析构函数),具体方案如下:下:在该对象类添加一个智能指针类型的私有成员变量在该对象类添加一个智能指针类型的私有成员变量:private:std:auto_ptr timer_arg_ipport_;这样,在该对象被销毁时,根据智能指针的特性,由这样,在该对象被销毁时,根据智能指针的特性,由timer_arg_ipport_这个变量持
23、有的资源会自动被释放。这样,我们就不用担心资源这个变量持有的资源会自动被释放。这样,我们就不用担心资源的泄漏问题了。的泄漏问题了。相应的,设置定时器的代码就变为类似如下了:相应的,设置定时器的代码就变为类似如下了:timer_arg_ipport_ = std:auto_ptr(new TString(ipport);this-setTimer(timerId, pending_user_enroll_timer_id, 30, 1, / 设置一个设置一个30秒的定时器,定时秒的定时器,定时1次次timer_arg_ipport_.get();同时,在同时,在onTimerOut函数里也不用进
24、行函数里也不用进行delete的调用了。的调用了。【举一反三举一反三】资源的分配与释放不在同一个地方,可以考虑使用智能指针资源的分配与释放不在同一个地方,可以考虑使用智能指针Page 15Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.类型转换不当:删除的对象类型不正确【问题描述问题描述】网上问题案例:voidvoid* * CPtrList:RemoveHead() / / 返回为返回为voidvoid* * 无类型方式的通用指针无类型方式的通用指针typedef struct tagPropInfo / m_PropList中的节点,其中的
25、成员变量有自己的构造和析构函数CString PropName;CString PropValue; PropInfo;while (!m_PropList-IsEmpty() delete m_PropList-RemoveHead(); delete m_PropList-RemoveHead();【问题定位问题定位】调用delete m_PropList-RemoveHead()时,C+编译器认为delete一个void*的对象,并没有调用类PropInfo的析构函数,导致内存泄漏【纠正措施纠正措施】 将m_PropList-RemoveHead()的返回值强制进行一次类型转换【举一反三
26、举一反三】尽量避免将多个功能写作一条语句中,如果上面的代码使用了临时变量:voidvoid* * tempPropInfo = m_PropList-RemoveHead(); tempPropInfo = m_PropList-RemoveHead();delete (PropInfodelete (PropInfo* *)tempPropInfo;)tempPropInfo;则很容易发现tempPropInfo的类型不正确,就不会忘记进行类型转换了Page 16Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.对需要释放的指针重新赋值【问题描
27、述问题描述】代码飞检发现如下代码:struct FileInfo * pdbffile = new struct FileInfo; pfile = pdbffile;pfile = pdbffile; 【问题定位问题定位】pfile不为空,pfile以前指向的内存丢失了【举一反三举一反三】尽量不要对指针重新赋值。对指针重新赋值,首先考虑设计是否合理;除建立链表等特殊情况外,不要将非空指针作为左值。Page 17Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.宏里面有return语句【问题描述问题描述】代码飞检发现如下代码:头文件中的宏定义如下
28、:#define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) do POINTER = newnew CONSTRUCTOR; if (POINTER = 0 ) error = ENOMEM; return return RET_VAL while (0 )C+文件中的语句如下:ACE_NEW_RETURN( g_pProcTimer,CNMTimer(PROC,ONE_SECOND),IM_NM_NEW_FAIL);ACE_NEW_RETURN( g_pBPTimer,CNMTimer(PROC,FIVE_SECOND),IM_NM_NEW_FA
29、IL)ACE_NEW_RETURN( g_pBPTimer,CNMTimer(PROC,FIVE_SECOND),IM_NM_NEW_FAIL)【问题定位问题定位】当第二个ACE_NEW_RETURN语句在宏里面出错直接return时,第一个ACE_NEW_RETURN语句申请的内存泄漏了!Page 18Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.宏里面有return语句(续1)【问题描述问题描述】代码飞检发现如下代码:头文件中的宏定义如下:#define ERROR_HANDLE_RETURN(CONDITION,RETURNVALUE)
30、if(true=(CONDITION)return return RETURNVALUERETURNVALUE;C+文件中的语句如下:NEW(pShell,MessageHandlerShell);NEW(pShell,MessageHandlerShell);IRegisting* pRegisting = pService-getFeatureRegist() ; ERROR_HANDLE_RETURN(NULL=pRegisting, False); ERROR_HANDLE_RETURN(NULL=pRegisting, False); 【问题定位问题定位】一旦宏ERROR_HANDL
31、E_RETURN执行retrurn,前面分配的内存pShell就会泄漏。【举一反三举一反三】小心使用有return语句的宏,确保前面资源已经释放。Page 19Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.宏里面有return语句(续2)【问题描述问题描述】代码飞检发现如下代码:/ 将Session从Busy Session池移出,放入Free Session池ERROR_HANDLE_RETURN(FALSE=this-pop(enum_session_pool_busy,pSession),FALSE);ERROR_HANDLE_RETU
32、RN(FALSE=this-onIdleSession(pSession), FALSE);ERROR_HANDLE_RETURN(FALSE=this-onIdleSession(pSession), FALSE);ERROR_HANDLE_RETURN(False=this-push(enum_session_pool_free,pSession),False); 【问题定位问题定位】一旦从第2个ERROR_HANDLE_RETURN处退出,pSession已经从Busy Session池移出,但并没有放入Free Session池,也没有被删除【举一反三举一反三】宏里面有return语句
33、,很容易造成各种隐患,产品最好禁止这种做法。 Page 20Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.C+的析构函数没有释放内存【问题描述问题描述】代码飞检发现如下代码:CDBOperation:CDBOperation() 【问题定位问题定位】上面代码忘记对类成员指针删除,导致内存泄漏【纠正措施纠正措施】 修改代码为:CDBOperation:CDBOperation() If (NULL != m_pmmlProcssTimeCost) DELETE(m_pmmlProcssTimeCost); 【举一反三举一反三】类或函数申请的资源
34、应该在退出时释放Page 21Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.使用复杂语句或函数:多个判断条件写在一起【问题描述问题描述】代码飞检发现如下代码:char* pszInfoBuf = VOS_NULLPTR;char* pszInfoBuf2 = VOS_NULLPTR;pszInfoBuf = (charpszInfoBuf = (char* *)VOS_Malloc(MID_BVLAN, ulBuffLen); )VOS_Malloc(MID_BVLAN, ulBuffLen); pszInfoBuf2 = (char*)VO
35、S_Malloc(MID_BVLAN, ulBuffLen);if ( (pszInfoBuf = NULL) | (pszInfoBuf2 = NULL ) )return VOS_ERR;return VOS_ERR;【问题定位问题定位】当pszInfoBuf申请成功,但pszInfoBuf2申请失败时,进入此分支,pszInfoBuf指向的内存泄漏了 【举一反三举一反三】 不要将多个判断条件写在一起 。Page 22Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.使用复杂语句或函数:没有及时释放不使用的内存【问题描述问题描述】代码飞检发现
36、如下代码:ULONG CQC_CmdNoApplySystem(VOID* pMsgRcv,VOID* ppMsgSnd)代码太长,这里不引用。【问题定位问题定位】该函数共531行,函数开头就申请了pMsgRcv指针,从128行开始,即不再使用这个指针,但没有及时释放,一直到531行函数完全结束时才释放pMsgRcv指针。但在128行以后,共有9处异常退出,有5处释放了pMsgRcv指针,有4处却没有释放pMsgRcv指针。【举一反三举一反三】1。尽量避免过于复杂的函数2。养成及时释放内存和资源的习惯。Page 23Huawei Confidential HUAWEI TECHNOLOGIES
37、 CO., LTD.使用复杂语句或函数:一个语句,多个分配【问题描述问题描述】网上问题案例Fun(shared_ptr(new Widget), shared_ptr(new Widget)Fun(shared_ptr(new Widget), shared_ptr(new Widget)【问题定位问题定位】 函数Fun的两个入参都是智能指针,会被自动回收,通常不可能出现内存泄漏。但C标准没有强制规定函数参数的计算顺序,不同的编译器处理不同。编译器可能将上面代码细化操作为:对第一个参数执行new Widget,分配内存对第二个参数执行new Widget,分配内存对第一个参数执行构造函数,实例
38、化对第二个参数执行构造函数,实例化如果第3步失败,抛出异常,第1步申请的内存被自动回收,但第2步分配的内存就丢失了【纠正措施纠正措施】修改代码为:shared_ptrsp1(new Widget);shared_ptrsp2(new Widget);Fun(sp1,sp2);【举一反三举一反三】不要在一条语句中分配一个以上的资源,应该在自己的代码语句中这些显式的资源分配(比如new),而且每次都应该马上将分配的资源赋予管理对象(比如shared_ptr)。Page 24Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.非空指针作为左值:需要释放的
39、指针参与运算【问题描述问题描述】网上问题案例:while (NULL != (lpSrcStrlpSrcStr = strchr(lpSrcStr,.) lpBackStr = lpSrcStr+1; if (lpCheck255) free(lpSrcStr); return 0; else ulResult = (ulResult 8 ) +lpCheck; lpSrcStr = lpBackStr; / lpSrcStrlpSrcStr = lpBackStr; / lpSrcStr指针发生了变化!指针发生了变化! lpForStr = lpSrcStr; free(lpSrcStr);
40、free(lpSrcStr); 【问题定位问题定位】 lpSrcStr参与运算后,指向的地址已经不是最初使用malloc申请的内存了,free(lpSrcStr)失败【举一反三举一反三】使用临时变量参与指针运算,确保原指针不会被修改。需要释放的指针禁止参与运算Page 25Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.缺少分支处理【问题描述问题描述】网上问题案例:pMsg = g_InstantQueue.at(j);mu = SortOperation(pMsg);if (mu = 0) if (mu = 0) ret = 0; ret =
41、 0; elseif (mu = 5)ret = SendMsgToMu(pMsg, mu-1);if (ret = 0) g_InstantQueue.removeAt(j);【问题定位问题定位】mu5的分支,根本没有考虑,内存泄漏【举一反三举一反三】if条件的所有分支都必须考虑清楚Page 26Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放队列中的内存【问题描述问题描述】前面同一个案例前面同一个案例:pMsg = g_InstantQueue.at(j);mu = SortOperation(pMsg);if (mu = 0)re
42、t = 0; elseif (mu = 5)ret = SendMsgToMu(pMsg, mu-1);if (ret = 0) g_InstantQueue.removeAt(j);g_InstantQueue.removeAt(j);【问题定位问题定位】如果SendMsgToMu失败(ret100) if (iFileCount 100) break; break; if (True = cacheAlarm(pMsgPara-m_alarmReport) DELETE(pMsg); else sendMessage(pMsg);/把消息挂入消息队列中【问题定位问题定位】条件if (iFi
43、leCount 100)为真,导致break时,内存泄漏。 【纠正措施纠正措施】将申请内存的语句NEW(pMsg, TMsg)移动到判断语句if (iFileCount 100)后面【举一反三举一反三】如果在程序块中存在异常检查或退出机制,应放在最前面,这条控制语句前面的代码必须与异常检查或退出条件相关。Page 28Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.基类中没有定义虚析构函数【问题描述问题描述】代码飞检人员发现某产品缺陷跟踪库中这样解决某网上问题:class A / virtual A() / virtual A() / 问题定位
44、:析构函数中打印Log信息内存越界,删除析构函数【问题定位问题定位】检查Class A的子类:class B: public AB() ; / 子类B定义了自己的析构函数; 如果出现下面的代码:A A * * p = new B; p = new B; delete p;delete p;声明的对象p的类型为基类A,但实际类型为子类B,所以delete p时,编译器认为删除的是Class A的对象,则调用Class A的析构函数(编译器对A添加的默认析构函数),而不调用B的析构函数,这样B里面申请的内存就泄漏了【纠正措施纠正措施】在基类A中增加一个空的虚析构函数,则编译器会自动调用B的析构函数
45、【举一反三举一反三】只要在类中有虚函数,就必须有虚析构函数Page 29Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.基类中没有定义虚析构函数(续)【问题描述问题描述】使用purify发现如下代码内存泄漏:void CAlarmer:destroyAlarmInfo(IAlarmInfo* pAlarmInfo) DELETE(pCAI);【问题定位问题定位】为了减少耦合,对外暴露的是IAlarmInfo的纯虚接口。但内部的实现是CAlarmInfo。在创建时创建一个CAlarmInfo而后强制转换成IAlarmInfo返回。典型的使用基类指
46、针进行删除,由于基类没有设置虚析构函数,导致派生类的析构函数没有调用,这样派生类CAlarmInfo里面申请的内存就泄漏了。【纠正措施纠正措施】在基类IAlarmInfo中析构函数设置为虚【举一反三举一反三】允许通过基类的指针进行删除操作,则基类的析构函数必须是公用且虚拟。Page 30Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.未及时加入列表,异常抛出时内存泄漏【问题描述问题描述】CPArray类为管理对象指针的列表,具有自动释放功能。类为管理对象指针的列表,具有自动释放功能。程序正常情况下,加入程序正常情况下,加入CPArray中的对象
47、可以得到释放,在有异常发生的时候,对象的不到释放,造成内存泄漏。中的对象可以得到释放,在有异常发生的时候,对象的不到释放,造成内存泄漏。【问题定位问题定位】分析下面的代码段,发现分析下面的代码段,发现new的的pObj已经放到了自动释放列表中,粗看代码没什么问题;已经放到了自动释放列表中,粗看代码没什么问题;.CPArray myArray(AUTO_FREE);CMyObject *pObj = NULL;for(int i = 0; i m_ID = i;. Function1(pObj); . myArray.Add(pObj);.跟踪跟踪Function1函数,在该函数内有异常抛出,导
48、致函数,在该函数内有异常抛出,导致myArray.Add(pObj)语句没有被执行,造成语句没有被执行,造成pObj对象没有被释放对象没有被释放。Page 31Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.未及时加入列表,异常抛出时内存泄漏(续)【纠正措施纠正措施】对象创建以后,首先加入到自动释放列表中,再执行其他操作;对象创建以后,首先加入到自动释放列表中,再执行其他操作;以上代码修改为:以上代码修改为:.CPArray myArray(AUTO_FREE);CMyObject *pObj = NULL;for(int i = 0; i m
49、_ID = i;. Function1(pObj); . 无论函数无论函数Function1()是否有异常,都能保证对象得到释放。是否有异常,都能保证对象得到释放。【举一反三举一反三】使用自动释放列表的程序,要第一时间将新创建对象加入到列表中;调用函数时,要考虑到函数是否会使用自动释放列表的程序,要第一时间将新创建对象加入到列表中;调用函数时,要考虑到函数是否会抛出异常。抛出异常。Page 32Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放队列中的内存【问题描述问题描述】发现加载发现加载*软件命令出现内存泄漏现象。软件命令出现内存泄漏
50、现象。【问题定位问题定位】分析下面的代码段,发现删除队列节点时,没有删除节点对应的内存分析下面的代码段,发现删除队列节点时,没有删除节点对应的内存。/获得加载命令附加信息指针获得加载命令附加信息指针CDldAllSwAddInfo *pDldAllSwInfo = (CDldAllSwAddInfo *)(g_TaskId.GetDataPtr(iTaskId);./清除已经完成加载的单板信息清除已经完成加载的单板信息pDldAllSwInfo-m_pBoardReportList.RemoveAt(0);pDldAllSwInfo-m_pBoardReportList.SetSize(iSi
51、ze-1);pDldAllSwInfo-m_pBoardReportList.FreeExtra();Page 33Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.没有释放队列中的内存(续)【纠正措施纠正措施】添加如下代码,问题解决:添加如下代码,问题解决:if(pDldAllSwInfo-m_pBoardReportList0 != NULL) delete pDldAllSwInfo-m_pBoardReportList0; pDldAllSwInfo-m_pBoardReportList0 = NULL;pDldAllSwInfo-m_p
52、BoardReportList.RemoveAt(0);pDldAllSwInfo-m_pBoardReportList.SetSize(iSize-1);pDldAllSwInfo-m_pBoardReportList.FreeExtra();【举一反三举一反三】处理链表或队列时,如果删除了其中的一个节点,还必须同处理链表或队列时,如果删除了其中的一个节点,还必须同时释放节点申请的内存时释放节点申请的内存 Page 34Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.重复连接数据库【问题描述问题描述】B020版本中,对版本中,对*模块进行系统
53、测试。某个模块进行系统测试。某个VOD处于上载中,点击处于上载中,点击,刷新其状态,则页面,刷新其状态,则页面运行非常慢,最终出现错误提示页面。运行非常慢,最终出现错误提示页面。【问题定位问题定位】在在*方法的方法的synchronizeCAStatus(ArrayList)方法中,在循环体内方法中,在循环体内new Operater(),即在循环体中创,即在循环体中创建数据库连接建数据库连接try for (int index = 0; index vodCAList.size(); index+) dbOper = new DBOperator(); 。 catch (Exception
54、e) 。finally dbOper.close();Page 35Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.重复连接数据库(续)【纠正措施纠正措施】数据库连接不能放在循环体中创建,否则会导致内存泄漏,数据库连接异常。将数据库连接不能放在循环体中创建,否则会导致内存泄漏,数据库连接异常。将dbOper = new DBOperator();语句提前到循环体外,语句提前到循环体外,try语句内语句内try dbOper = new DBOperator(); for (int index = 0; index vodCAList.size(
55、); index+) 。 catch (Exception e) 。finally dbOper.close();Page 36Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.对非POD对象进行memset操作【说明说明】POD(Plain Old Data)是普通旧式数据,如结构/枚举/成员指针等,内存字节是连续的。非POD类的内存字节不连续,中间可能包含vptr(虚函数指针表)等隐藏的数据【问题描述问题描述】网上问题案例shared_ptr p1(new int ),p2(new int ) ; memcpy(&p1,&p2
56、,sizeof(p1); memcpy(&p1,&p2,sizeof(p1); 【问题定位问题定位】内存泄漏:p2不会删除;内存访问失败:p1删除两次【举一反三举一反三】 C+编译器经常会在多态对象中嵌入一些隐藏数据(如vptr),多重继承/虚拟继承会添加更多的内部指针。不要直接对不要直接对C+C+的类进行的类进行memset/memcpymemset/memcpy等操作等操作,应尽量使用类自身提供的赋值/复制功能。Page 37Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.强制关闭线程:没有释放线程占据的资源【问题描述问题描
57、述】网上问题案例CShakeHand:CShakeHand()m_hdShakeThreadrecv = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ThreadProc_ShakeHands,this, NULL, &m_ulShakeThreadID);CShakeHand:CShakeHand()TerminateThread(m_hdShakeThreadrecv, 0); /TerminateThread(m_hdShakeThreadrecv, 0); /强制关闭强制关闭CloseHandle(m_hdShakeThreadr
58、ecv);【问题定位问题定位】线程被强制关闭,导致线程内部资源/内存泄漏【举一反三举一反三】使用事件或信号量通知线程,确保线程调用自身的退出函数Page 38Huawei Confidential HUAWEI TECHNOLOGIES CO., LTD.预防内存泄漏的方法:RAIIRAII是英文是英文Resource Acquisition Is Initialization的缩写。意为在对象构造时获取资源,接着控的缩写。意为在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终有效,最后在对象析构的时候释放资源。制对资源的访问使之在对象的生命周期内始终有效,最后在对象析构的时
59、候释放资源。RAII有两大有两大好处:好处:不需要显式地释放资源。即使是使用资源的方法的控制结构发生了改变,例如在中间插入return或者抛出异常,我们能确定资源肯定会在对象析构的时候被释放。对象所需的资源在其生命期内始终保持有效我们可以说,此时这个类维护了一个invariant,通过该对象使用资源时,不必检查资源有效性,可以简化逻辑。我司有的项目组规定,禁止在函数中间退出,必须我司有的项目组规定,禁止在函数中间退出,必须goto到函数结尾;在函数结尾统一释放所有的到函数结尾;在函数结尾统一释放所有的资源。这是在资源。这是在C语言中变通实现语言中变通实现RAII的方法,这种情况下允许使用的方法
60、,这种情况下允许使用goto语句。语句。代码飞检发现,很多产品之所以被检查出大量的内存泄漏问题,主要原因是释放内存的规则混乱。代码飞检发现,很多产品之所以被检查出大量的内存泄漏问题,主要原因是释放内存的规则混乱。有的函数自己申请内存,自己释放;有的申请后,传入子程序中,子程序使用并释放;有的由子程有的函数自己申请内存,自己释放;有的申请后,传入子程序中,子程序使用并释放;有的由子程序申请内存并返回父程序,层层使用后在某一个函数内释放。序申请内存并返回父程序,层层使用后在某一个函数内释放。华为公司编程规范要求:华为公司编程规范要求:“规则规则9-5:过程:过程/函数中分配的内存,在过程函数中分配的内存,在过程/函数退出之前要函数退出之前要释放释放” 。RAII其实就是遵守这条规则的
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 三农产品品牌培育方案手册
- 医疗卫生行业医疗信息化与智能诊断方案
- 医疗设备行业质量控制与监管体系方案
- 高效率日常行政事务文书指南
- 物联网行业智能家居设备互联互通方案
- 能源储存技术手册
- 餐饮企业运营管理与服务指南
- 辽宁2025年辽宁石化职业技术学院赴高校现场招聘3人笔试历年参考题库附带答案详解
- 自贡2025年第一批四川自贡市消防救援支队招录聘用制消防员25人笔试历年参考题库附带答案详解
- 绍兴浙江绍兴市急救中心招聘编外工作人员笔试历年参考题库附带答案详解
- CB/T 3155-1994带缆辅助索
- 鸟类教学讲解课件
- 斐波那契数列与黄金分割 课件
- 乙类互补推挽功率放大电路课件
- 2-管道仪表流程图PID
- 高中班会课:趣味知识竞赛课件
- 特种设备吨叉车设计计算书
- (精选word)洪恩识字-生字卡片1-200
- XX市三级公立综合医院绩效考核指标评分细则
- 监理平行检查记录表(最新全套)电子版本
- 押金收据条(通用版)
评论
0/150
提交评论