[其他] 内存泄漏以及原因

[复制链接]
 楼主| 小夏天的大西瓜 发表于 2024-6-18 08:26 | 显示全部楼层 |阅读模式
一、什么是内存泄漏?
在C语言中,我们可以使用malloc、calloc、realloc等函数来动态地申请内存空间,这些内存空间是从堆(heap)中分配的,与程序的生命周期无关,只有当我们显式地调用free函数来释放这些内存空间时,它们才会被回收。这样,我们就可以根据需要动态地调整内存的大小和数量,提高内存的利用率和程序的灵活性。

但是,这种动态内存分配的方式也带来了一些风险,就是如果我们在使用完动态分配的内存空间后,忘记或者无法释放它们,那么这些内存空间就会一直占用着系统的内存资源,无法被其他程序使用,这就是内存泄漏(memory leak)。

简单的内存泄漏示例代码:

  1. 1#include <stdlib.h>  
  2. 2
  3. 3void allocateMemory() {  
  4. 4    int* ptr = (int*)malloc(sizeof(int));  
  5. 5    if (ptr == NULL) {  
  6. 6        exit(1);  
  7. 7    }  
  8. 8    *ptr = 10;  
  9. 9    // 注意:这里缺少了free(ptr)的调用,导致内存泄漏  
  10. 10}  
  11. 11
  12. 12int main() {  
  13. 13    for (int i = 0; i < 10000; i++) {  
  14. 14        allocateMemory();  
  15. 15    }  
  16. 16    return 0;  
  17. 17}

上面的例子中,allocateMemory 函数使用 malloc 分配了一块内存,但之后并没有调用 free 释放这块内存。因此,每次调用 allocateMemory 函数时,都会有一块内存无法被释放,这就是内存泄漏。

二、内存泄漏的常见原因
1.内存泄漏的常见原因
(1)忘记释放内存

当使用malloc、calloc或realloc等函数分配内存后,必须在使用完内存后使用free来释放它。如果忘记释放,就会导致内存泄漏。

示例代码:

  1. 1#include <stdlib.h>  
  2. 2
  3. 3void forgetToFree() {  
  4. 4    int* ptr = (int*)malloc(sizeof(int));  
  5. 5    if (ptr != NULL) {  
  6. 6        *ptr = 10;  
  7. 7        // 忘记调用 free(ptr)  
  8. 8    }  
  9. 9}  
  10. 10
  11. 11int main(int argc, char *argv[]) {  
  12. 12    for (int i = 0; i < 10000; i++) {  
  13. 13        forgetToFree();  
  14. 14    }  
  15. 15    return 0;  
  16. 16}

(2)重复释放

尝试多次释放同一块内存是非法的,可能导致程序崩溃。

示例代码:

  1. 1#include <stdlib.h>  
  2. 2
  3. 3void doubleFree() {  
  4. 4    int* ptr = (int*)malloc(sizeof(int));  
  5. 5    if (ptr != NULL) {  
  6. 6        free(ptr);  
  7. 7        // 重复释放同一块内存  
  8. 8        free(ptr);
  9. 9    }  
  10. 10}  
  11. 11
  12. 12int main(int argc, char *argv[]) {  
  13. 13    doubleFree();  
  14. 14    return 0;  
  15. 15}

(3)内存泄漏在函数中

在函数内部分配的内存,如果没有被返回给调用者,调用者就无法释放它。

示例代码:

  1. 1#include <stdlib.h>  
  2. 2
  3. 3void allocateInFunction() {  
  4. 4    int* ptr = (int*)malloc(sizeof(int));  
  5. 5    if (ptr != NULL) {  
  6. 6        // ptr 没有返回给调用者,导致内存泄漏  
  7. 7        *ptr = 10;  
  8. 8    }  
  9. 9}  
  10. 10
  11. 11int main(int argc, char *argv[]) {   
  12. 12    allocateInFunction();  
  13. 13    // 无法释放 allocateInFunction 中分配的内存  
  14. 14    return 0;  
  15. 15}

(4)指针丢失

如果丢失了指向已分配内存的指针,那么这块内存就无法被释放。

示例代码:

  1. 1#include <stdlib.h>  
  2. 2int* someOtherFunction() {  
  3. 3    // 假设这个函数返回一个新的指针  
  4. 4    int* newPtr = (int*)malloc(sizeof(int));  
  5. 5    return newPtr;  
  6. 6}  
  7. 7
  8. 8void loseReference() {  
  9. 9    int* ptr = (int*)malloc(sizeof(int));  
  10. 10    if (ptr != NULL) {  
  11. 11        *ptr = 10;  
  12. 12        // 假设ptr被用于某个全局数据结构或传递给其他函数  
  13. 13        // ...  
  14. 14        // 然后ptr的引用丢失了,例如它指向的内存被另一个指针覆盖  
  15. 15        // 假设这个函数返回一个新的指针  
  16. 16        int* newPtr = someOtherFunction();
  17. 17        // 现在ptr指向了新的内存,原先的内存泄漏了  
  18. 18        ptr = newPtr;
  19. 19        // 或者ptr可能被置为NULL,或者超出了其作用域  
  20. 20    }  
  21. 21}  
  22. 22
  23. 23int main(int argc, char *argv[]) {  
  24. 24    // 调用函数,ptr曾经指向一块内存  
  25. 25    loseReference();  
  26. 26    // 但由于在某处丢失了ptr的引用,这块内存无法被释放,导致内存泄漏  
  27. 27    return 0;  
  28. 28}

moore21 发表于 2024-6-21 13:13 | 显示全部楼层
用cppcheck 工具很容易查到C代码里的内存泄漏。
OKAKAKO 发表于 2024-6-22 19:51 | 显示全部楼层
尝试多次释放同一块内存是非法的,可能导致程序崩溃。
中国龙芯CDX 发表于 2024-6-26 14:09 | 显示全部楼层
这种动态内存分配的方式也带来了一些风险,就是如果我们在使用完动态分配的内存空间后,忘记或者无法释放它们,那么这些内存空间就会一直占用着系统的内存资源,无法被其他程序使用,这就是内存泄漏(memory leak)。
forgot 发表于 2024-6-27 08:39 | 显示全部楼层
很多复杂的程序动态分配内存到后面很多都不能保证一定得到释放。
LOVEEVER 发表于 2024-7-15 14:46 | 显示全部楼层
尝试多次释放同一块内存是非法的导致程序崩溃
szt1993 发表于 2024-7-17 19:24 | 显示全部楼层
内存空间就会一直占用着系统的内存资源,无法被其他程序使用,这就是内存泄漏
您需要登录后才可以回帖 登录 | 注册

本版积分规则

257

主题

2238

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部

257

主题

2238

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部