《常见的内存错误及其对策》由会员分享,可在线阅读,更多相关《常见的内存错误及其对策(15页珍藏版)》请在金锄头文库上搜索。
1、2024/7/19常见的内存错误及其对策常见的内存错误及其对策 特点特点特点特点编译器不能自动发现这类错误,通常是在程序运行时编译器不能自动发现这类错误,通常是在程序运行时编译器不能自动发现这类错误,通常是在程序运行时编译器不能自动发现这类错误,通常是在程序运行时才能捕捉到才能捕捉到才能捕捉到才能捕捉到时隐时现,无明显症状时隐时现,无明显症状时隐时现,无明显症状时隐时现,无明显症状 分类分类分类分类内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未
2、初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,并且已经初始化,但操作越过了内存内存分配成功,并且已经初始化,但操作越过了内存内存分配成功,并且已经初始化,但操作越过了内存内存分配成功,并且已经初始化,但操作越过了内存的边界的边界的边界的边界忘记了释放内存,造成内存泄漏忘记了释放内存,造成内存泄漏忘记了释放内存,造成内存泄漏忘记了释放内存,造成内存泄漏释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误常见错误常见错误1 1:内存分配未成功,却使用了它内存
3、分配未成功,却使用了它内存分配未成功,却使用了它内存分配未成功,却使用了它 起因起因起因起因没有意识到内存分配会不成功没有意识到内存分配会不成功没有意识到内存分配会不成功没有意识到内存分配会不成功编程新手容易犯编程新手容易犯编程新手容易犯编程新手容易犯 解决对策解决对策解决对策解决对策在使用内存之前,检查指针是否为空指针(在使用内存之前,检查指针是否为空指针(在使用内存之前,检查指针是否为空指针(在使用内存之前,检查指针是否为空指针(NULLNULL) ifif (p = NULL) (p = NULL) printf(No enough memory!n);printf(No enough
4、memory!n); exit(0); exit(0); 2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误2 2:内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它 起因起因没有初始化的观念没有初始化的观念没有初始化的观念没有初始化的观念误以为内存的默认值全为误以为内存的默认值全为误以为内存的默认值全为误以为内存的默认值全为0 0 0 0 解决对策解决对策即使是赋即使是赋即使是赋即使是赋0 0 0 0值也不可省略,不要嫌麻烦值也不可省略,不要嫌麻烦值也不可省略,不要嫌麻
5、烦值也不可省略,不要嫌麻烦2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误3:内存分配成功,并且已经初始化,但操作越过了内存分配成功,并且已经初始化,但操作越过了内存分配成功,并且已经初始化,但操作越过了内存分配成功,并且已经初始化,但操作越过了内存的边界内存的边界内存的边界内存的边界例如:例如:例如:例如:使用数组时经常发生下标使用数组时经常发生下标使用数组时经常发生下标使用数组时经常发生下标“ “多多多多1”1”或者或者或者或者“ “少少少少1”1”的操作的操作的操作的操作 解决对策:解决对策:在在在在forfor语句中,注意循环次数不要搞错语句中,注意循环
6、次数不要搞错语句中,注意循环次数不要搞错语句中,注意循环次数不要搞错2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误4:忘记释放内存,造成忘记释放内存,造成忘记释放内存,造成忘记释放内存,造成内存泄漏内存泄漏内存泄漏内存泄漏(Memory Leak)(Memory Leak)“ “内存泄露内存泄露内存泄露内存泄露” ”一词类似一词类似一词类似一词类似“ “原料泄露原料泄露原料泄露原料泄露” ”泄露出去的原料不能被利用,导致生产过程中泄露出去的原料不能被利用,导致生产过程中泄露出去的原料不能被利用,导致生产过程中泄露出去的原料不能被利用,导致生产过程中原料不足原料
7、不足原料不足原料不足好比借东西不还好比借东西不还好比借东西不还好比借东西不还如果申请来的内存不用,别的程序也不能用,如果申请来的内存不用,别的程序也不能用,如果申请来的内存不用,别的程序也不能用,如果申请来的内存不用,别的程序也不能用,就好像这块内存泄露出去一样,造成浪费就好像这块内存泄露出去一样,造成浪费就好像这块内存泄露出去一样,造成浪费就好像这块内存泄露出去一样,造成浪费2024/7/19常见的内存错误及其对策常见的内存错误及其对策 特征特征含有这种错误的函数,每被调用一次,就丢失含有这种错误的函数,每被调用一次,就丢失含有这种错误的函数,每被调用一次,就丢失含有这种错误的函数,每被调用
8、一次,就丢失一块内存(制造内存垃圾)一块内存(制造内存垃圾)一块内存(制造内存垃圾)一块内存(制造内存垃圾)刚开始时,系统内存充足,看不到任何错误刚开始时,系统内存充足,看不到任何错误刚开始时,系统内存充足,看不到任何错误刚开始时,系统内存充足,看不到任何错误当系统运行相当一段时间后,就会突然死掉,当系统运行相当一段时间后,就会突然死掉,当系统运行相当一段时间后,就会突然死掉,当系统运行相当一段时间后,就会突然死掉,出现提示:内存耗尽出现提示:内存耗尽出现提示:内存耗尽出现提示:内存耗尽需长期稳定运行的服务程序对内存泄漏最敏感需长期稳定运行的服务程序对内存泄漏最敏感需长期稳定运行的服务程序对内
9、存泄漏最敏感需长期稳定运行的服务程序对内存泄漏最敏感严重程度取决于严重程度取决于严重程度取决于严重程度取决于 每次遗留内存垃圾的多少每次遗留内存垃圾的多少每次遗留内存垃圾的多少每次遗留内存垃圾的多少 代码被调用的次数代码被调用的次数代码被调用的次数代码被调用的次数2024/7/19常见的内存错误及其对策常见的内存错误及其对策 解决对策解决对策解决对策解决对策在需要的时候才在需要的时候才在需要的时候才在需要的时候才mallocmalloc,并尽量减少,并尽量减少,并尽量减少,并尽量减少mallocmalloc的次数的次数的次数的次数 mallocmalloc的执行效率就不高,过多的的执行效率就不
10、高,过多的的执行效率就不高,过多的的执行效率就不高,过多的mallocmalloc使程序性能下降使程序性能下降使程序性能下降使程序性能下降 能用自动变量解决的问题,就不要用能用自动变量解决的问题,就不要用能用自动变量解决的问题,就不要用能用自动变量解决的问题,就不要用mallocmalloc来解决来解决来解决来解决 mallocmalloc一般在大块内存分配和动态内存分配时使用一般在大块内存分配和动态内存分配时使用一般在大块内存分配和动态内存分配时使用一般在大块内存分配和动态内存分配时使用重复使用重复使用重复使用重复使用mallocmalloc申请到的内存申请到的内存申请到的内存申请到的内存尽
11、量让尽量让尽量让尽量让mallocmalloc和与之配套的和与之配套的和与之配套的和与之配套的freefree在一个函数或模块内在一个函数或模块内在一个函数或模块内在一个函数或模块内 尽量把尽量把尽量把尽量把mallocmalloc集中在函数的入口处,集中在函数的入口处,集中在函数的入口处,集中在函数的入口处,freefree集中在函数的出集中在函数的出集中在函数的出集中在函数的出口处口处口处口处 以上做法只能尽量降低产生泄露的概率。完全杜以上做法只能尽量降低产生泄露的概率。完全杜以上做法只能尽量降低产生泄露的概率。完全杜以上做法只能尽量降低产生泄露的概率。完全杜绝内存泄露,关键要靠程序员的细
12、心与责任感绝内存泄露,关键要靠程序员的细心与责任感绝内存泄露,关键要靠程序员的细心与责任感绝内存泄露,关键要靠程序员的细心与责任感2024/7/19一个例子一个例子voidvoid Init( Init(voidvoid) ) pszMyName=( pszMyName=(charchar*)malloc(256);*)malloc(256); ifif (pszMyName = NULL) (pszMyName = NULL) returnreturn; ; pszHerName=( pszHerName=(charchar*)malloc(256);*)malloc(256); ifif
13、(pszHerName = NULL) (pszHerName = NULL) returnreturn; ; pszHisName=( pszHisName=(charchar*)malloc(256);*)malloc(256); if if (pszHisName = NULL) (pszHisName = NULL) returnreturn; ; free(pszMyName);free(pszMyName); free(pszHerName); free(pszHerName); free(pszHisName); free(pszHisName); returnreturn; ;
14、 错在哪里!错在哪里!2024/7/19一个例子一个例子voidvoid Init( Init(voidvoid) ) pszMyName=( pszMyName=(charchar*)malloc(256);*)malloc(256); ifif (pszMyName = NULL) (pszMyName = NULL) returnreturn; ; pszHerName=( pszHerName=(charchar*)malloc(256);*)malloc(256); ifif (pszHerName = NULL) (pszHerName = NULL) free(pszMyName
15、);free(pszMyName); returnreturn; ; pszHisName=( pszHisName=(charchar*)malloc(256);*)malloc(256); if if (pszHisName = NULL) (pszHisName = NULL) free(pszMyName);free(pszMyName); free(pszHerName); free(pszHerName); returnreturn; ; free(pszMyName);free(pszMyName); free(pszHerName); free(pszHerName); fre
16、e(pszHisName); free(pszHisName); returnreturn; ; 2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误5 5:释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它 起因:起因:指针所指的内存被释放以后,并不表示指针会指针所指的内存被释放以后,并不表示指针会指针所指的内存被释放以后,并不表示指针会指针所指的内存被释放以后,并不表示指针会消亡消亡消亡消亡其地址仍然不变(非其地址仍然不变(非其地址仍然不变(非其地址仍然不变(非NULLNULL),只是该地址对应),只是该地址对应),
17、只是该地址对应),只是该地址对应的内存是垃圾的内存是垃圾的内存是垃圾的内存是垃圾指向垃圾内存的指针是指向垃圾内存的指针是指向垃圾内存的指针是指向垃圾内存的指针是“野指针野指针野指针野指针”free(ptr);free(ptr); ifif (ptr != NULL) (ptr != NULL) /不起作用不起作用不起作用不起作用 2024/7/19常见的内存错误及其对策常见的内存错误及其对策 charchar* GetInput(* GetInput(voidvoid) ) charchar s80; s80;scanf(scanf( %s%s , s);, s);returnreturn s
18、; s; warning C4172: returning address of local warning C4172: returning address of local variable or temporaryvariable or temporary 输出乱码输出乱码输出乱码输出乱码 voidvoid GetInput( GetInput(charchar* s)* s) scanf(scanf( %s%s , s);, s); 错在哪里!错在哪里!不能把局部变量的地址作为返不能把局部变量的地址作为返不能把局部变量的地址作为返不能把局部变量的地址作为返回值返回回值返回回值返回回值返
19、回函数返回后,局部变量被释放,函数返回后,局部变量被释放,该地址的内存会被挪做它用该地址的内存会被挪做它用2024/7/19常见的内存错误及其对策常见的内存错误及其对策# #includeinclude # #includeinclude voidvoid GetInput( GetInput(charchar *p) *p) p = (p = (charchar * *)malloc(100); )malloc(100); 程序崩溃,函数不能传递动态分配的内存程序崩溃,函数不能传递动态分配的内存程序崩溃,函数不能传递动态分配的内存程序崩溃,函数不能传递动态分配的内存? ? ? ? voidv
20、oid GetInput( GetInput(charchar *p)p) * *p = (p = (char *char *)malloc(100); )malloc(100); 2024/7/19常见的内存错误及其对策常见的内存错误及其对策 常见错误常见错误5解决对策解决对策尽量把尽量把尽量把尽量把mallocmalloc集中在函数的入口处,集中在函数的入口处,集中在函数的入口处,集中在函数的入口处,freefree集中集中集中集中在函数的出口处在函数的出口处在函数的出口处在函数的出口处如果如果如果如果freefree不能放在函数出口处不能放在函数出口处不能放在函数出口处不能放在函数出口处
21、, ,则指针则指针则指针则指针freefree后后后后立即设置为立即设置为立即设置为立即设置为NULLNULL不要把局部变量的地址作为返回值返回,因为该不要把局部变量的地址作为返回值返回,因为该不要把局部变量的地址作为返回值返回,因为该不要把局部变量的地址作为返回值返回,因为该内存在函数体结束时被自动销毁内存在函数体结束时被自动销毁内存在函数体结束时被自动销毁内存在函数体结束时被自动销毁指针要么初始化为指针要么初始化为指针要么初始化为指针要么初始化为NULLNULL,要么是其指向合法的,要么是其指向合法的,要么是其指向合法的,要么是其指向合法的内存内存内存内存2024/7/19非法内存操作非法
22、内存操作 起因起因内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配未成功,却使用了它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,但是尚未初始化就引用它内存分配成功,并且已经初始化,但操作越过内存分配成功,并且已经初始化,但操作越过内存分配成功,并且已经初始化,但操作越过内存分配成功,并且已经初始化,但操作越过了内存的边界了内存的边界了内存的边界了内存的边界释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它释放了内存,却继续使用它 基本特征基本特征代码访问了不
23、该访问的内存地址代码访问了不该访问的内存地址代码访问了不该访问的内存地址代码访问了不该访问的内存地址2024/7/19非法内存操作非法内存操作 后果后果 宣布安乐死:宣布安乐死:“该程序执行了非法操作,即将该程序执行了非法操作,即将关闭关闭”几乎全是由指针混乱导致的几乎全是由指针混乱导致的几乎全是由指针混乱导致的几乎全是由指针混乱导致的少数情况下,如在硬件驱动程序中的内存问题会少数情况下,如在硬件驱动程序中的内存问题会少数情况下,如在硬件驱动程序中的内存问题会少数情况下,如在硬件驱动程序中的内存问题会造成操作系统的死亡造成操作系统的死亡造成操作系统的死亡造成操作系统的死亡最糟糕的不是系统死机,而是重要资料被窃取最糟糕的不是系统死机,而是重要资料被窃取最糟糕的不是系统死机,而是重要资料被窃取最糟糕的不是系统死机,而是重要资料被窃取