| 一、什么是内存泄漏? 在C语言中,我们可以使用malloc、calloc、realloc等函数来动态地申请内存空间,这些内存空间是从堆(heap)中分配的,与程序的生命周期无关,只有当我们显式地调用free函数来释放这些内存空间时,它们才会被回收。这样,我们就可以根据需要动态地调整内存的大小和数量,提高内存的利用率和程序的灵活性。
 
 但是,这种动态内存分配的方式也带来了一些风险,就是如果我们在使用完动态分配的内存空间后,忘记或者无法释放它们,那么这些内存空间就会一直占用着系统的内存资源,无法被其他程序使用,这就是内存泄漏(memory leak)。
 
 简单的内存泄漏示例代码:
 
 
  1#include <stdlib.h>  
 2
 3void allocateMemory() {  
 4    int* ptr = (int*)malloc(sizeof(int));  
 5    if (ptr == NULL) {  
 6        exit(1);  
 7    }  
 8    *ptr = 10;  
 9    // 注意:这里缺少了free(ptr)的调用,导致内存泄漏  
10}  
11
12int main() {  
13    for (int i = 0; i < 10000; i++) {  
14        allocateMemory();  
15    }  
16    return 0;  
17}
上面的例子中,allocateMemory 函数使用 malloc 分配了一块内存,但之后并没有调用 free 释放这块内存。因此,每次调用 allocateMemory 函数时,都会有一块内存无法被释放,这就是内存泄漏。
 
 二、内存泄漏的常见原因
 1.内存泄漏的常见原因
 (1)忘记释放内存
 
 当使用malloc、calloc或realloc等函数分配内存后,必须在使用完内存后使用free来释放它。如果忘记释放,就会导致内存泄漏。
 
 示例代码:
 
 
 1#include <stdlib.h>  
 2
 3void forgetToFree() {  
 4    int* ptr = (int*)malloc(sizeof(int));  
 5    if (ptr != NULL) {  
 6        *ptr = 10;  
 7        // 忘记调用 free(ptr)  
 8    }  
 9}  
10
11int main(int argc, char *argv[]) {  
12    for (int i = 0; i < 10000; i++) {  
13        forgetToFree();  
14    }  
15    return 0;  
16}
(2)重复释放
 
 尝试多次释放同一块内存是非法的,可能导致程序崩溃。
 
 示例代码:
 
 
  1#include <stdlib.h>  
 2
 3void doubleFree() {  
 4    int* ptr = (int*)malloc(sizeof(int));  
 5    if (ptr != NULL) {  
 6        free(ptr);  
 7        // 重复释放同一块内存  
 8        free(ptr); 
 9    }  
10}  
11
12int main(int argc, char *argv[]) {  
13    doubleFree();  
14    return 0;  
15}
(3)内存泄漏在函数中
 
 在函数内部分配的内存,如果没有被返回给调用者,调用者就无法释放它。
 
 示例代码:
 
 
  1#include <stdlib.h>  
 2
 3void allocateInFunction() {  
 4    int* ptr = (int*)malloc(sizeof(int));  
 5    if (ptr != NULL) {  
 6        // ptr 没有返回给调用者,导致内存泄漏  
 7        *ptr = 10;  
 8    }  
 9}  
10
11int main(int argc, char *argv[]) {   
12    allocateInFunction();  
13    // 无法释放 allocateInFunction 中分配的内存  
14    return 0;  
15}
(4)指针丢失
 
 如果丢失了指向已分配内存的指针,那么这块内存就无法被释放。
 
 示例代码:
 
 
  1#include <stdlib.h>  
 2int* someOtherFunction() {  
 3    // 假设这个函数返回一个新的指针  
 4    int* newPtr = (int*)malloc(sizeof(int));  
 5    return newPtr;  
 6}  
 7
 8void loseReference() {  
 9    int* ptr = (int*)malloc(sizeof(int));  
10    if (ptr != NULL) {  
11        *ptr = 10;  
12        // 假设ptr被用于某个全局数据结构或传递给其他函数  
13        // ...  
14        // 然后ptr的引用丢失了,例如它指向的内存被另一个指针覆盖  
15        // 假设这个函数返回一个新的指针  
16        int* newPtr = someOtherFunction(); 
17        // 现在ptr指向了新的内存,原先的内存泄漏了  
18        ptr = newPtr; 
19        // 或者ptr可能被置为NULL,或者超出了其作用域  
20    }  
21}  
22
23int main(int argc, char *argv[]) {  
24    // 调用函数,ptr曾经指向一块内存  
25    loseReference();  
26    // 但由于在某处丢失了ptr的引用,这块内存无法被释放,导致内存泄漏  
27    return 0;  
28}
 |