如何在 C/C++ 代码中避免,发现(以及修复)内存错误
(注,本文是翻译的http://www.cprogramming.com / 上的文章
How to Avoid, Find (and Fix) Memory Errors in your C/C++ Code
)作者: Naveen Gv
在 C/C++ 应用程序中,发生内存错误是很普遍的,它们会影响程序的稳定性和正确性。这些错误也将导致程序的错误。它们很难被复制,调试,以及改正它们将可能很昂贵。而有内存错误的没有程序会产生一些主要的问题,如内存泄漏会使程序运行是超出了内存大小而导致程序的终止。该文章将帮助理解在单一/多线程程序中挑战内存错误,以及提供怎么样使用工具去发现错误的帮助。
内存错误可以被广泛的分为两类: 堆内存错误 和 栈内存错误 。其中一些关于内存错误的挑战是:
• 堆和栈中的无效内存访问
• 内存泄漏
• 分配和释放的不匹配
• 未分配
• 堆和栈中未初始化的内存访问
• 交叉栈访问
无效内存访问
当一个读或者写指令引用未分配或已释放的内存时,该错误会发生。
char pStr = (char*)malloc(25); free(pStr); strcpy(pStr, “parallel programming”); // 对已释放的堆内存进行无效的写操作 |
内存泄漏
当分配的内存没有被释放时,内存泄漏会发生。如果这类泄漏发生得够厉害,那么泄漏实际将使程序运行出内存而导致提前终止。
char pStr = (char *)malloc(512); return; |
分配和释放的不匹配
当用不对应的释放函数来试图释放不是用相应的分配函数分配的内存时,该错误将发生。如
char *s = (char*)malloc(5); delete s; |
为了避免该类错误,确保使用正确的释放函数。在 C++ 中, new[] 是用于分配,其对应的释放函数是 delete[] 。在 C 语言中, malloc() , calloc() 和 realloc() 函数是用于分配内存,对应的释放函数是 free() 。相似地,在 Windows 上编程也有相应的 API 函数。
未分配
当释放已经释放过的内存时,将发生此类错误。这也叫做 “ 重复释放 ” 或 “ 双重释放 ” 。如
char* pStr = (char*)malloc(20); free(pStr); free(pStr); // 导致无效的释放 |
未初始化的内存访问
当在程序中一个未初始化的便利被读取时,该类错误缉拿个发生。
char *pStr = (char*)malloc(512); char c = pStr[0]; // pStr 指向的内容没有被初始化 |
void func() { int a; int b = a * 4; // 读取未初始化变量 } |
为了避免这类错误,要总是在使用变量之前初始化他们。
交叉栈访问
当一个线程访问另一个线程的栈内存时,发生此类错误。
main() { int *p; --------- CreateThread(., thread #1, .); // CreateThread(., thread #2, .); ------------- } Thread #1 { int q[1024]; p = q; q[0] = 1; } Thread #2 { *p = 2; // 交叉栈访问 } |
一个最简单的避免该类错误的方法就是,避免用全局变量来保存栈地址。
使用工具来查找内存错误
在市场上有很多内存错误检测工具;我使用 Intel Parallel Inspector 类查找内存错误。这是一个在单线程和多线程程序中都能使用的一个简单的和广泛的内存检测工具。
Inter Parallel Inspector 集成到了 Visual Studio 中。 Parallel Inspector 使用动态方法,这并不需要特殊的构建和编译。市场上不是所有的内存检测器都可以用来进行线程程序的性能分析。就像下图所示, Parallel Inspector 找出所有的内存错误和显示代码,模块和错误状态的代码行。
该工具的一个重要特性是它允许最终用户控制分析的深度。分析的深度越大,那分析将耗费更多的时间和使用更多的内存。
• 2x-20x – 分析发现内存泄漏
• 10x-40x – 分析标识错误的存在
• 20x-80x – 分析提供根原因信息来修复为题,以及增强摇摆指针检测
•
40x-160x -提供最明确的错误等级(包含系统库检测)
如果一个内存错误既不是相关的也不是要修复的,那有一个选项类抑制该错误。从配置设置里选择 suppressions 再选择相应的选项。
结论
在大的程序里手动发现内存错误是困难的。使用正确的工具自动地检测它们将是很有帮助的。 Parallel Inspector 是检查内存错误的最好工具的其中之一,其在窜行和并行程序中都有着很好的应用。