释放内存并避免泄漏
正确地清理资源。
释放内存并避免泄漏 是 CoddyKit 上的免费 C Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。
每次 malloc 都需要一次 free
堆内存在使用 free 释放之前会一直被保留。如果您没有释放某个堆块就丢失了指向它的唯一指针,这块内存就会泄漏。
泄漏会随着时间不断累积,并可能耗尽长时间运行的程序的内存。
int *a = malloc(100 * sizeof(*a));
/* ... use a ... */
free(a);free 实际做了什么
free(p) 会将堆块归还给分配器,以便重新使用。它不会改变 p 本身的值。
执行 free 后,p 仍然指向原来的地址,但该地址现在已经无效。访问它会导致未定义行为。
free(p);
/* p is now a dangling pointer */悬空指针陷阱
释放指针后仍然使用它,是一种释放后使用错误。程序可能一开始看似正常,随后却破坏数据或发生不可预测的崩溃。
一个简单的防护措施是在释放后立即将指针设为 NULL。
free(a);
a = NULL; /* now misuse is a clean NULL deref, easier to catch */重复释放会导致未定义行为
对同一个堆块调用两次 free 会破坏分配器的内部状态,并且通常会导致崩溃。
第一次释放后将指针设为 NULL 会有所帮助,因为 free(NULL) 明确保证是安全的,并且不会执行任何操作。
free(a);
a = NULL;
free(a); /* free(NULL) is a harmless no-op */只释放通过 malloc 分配的内存
传给 free 的指针必须来自 malloc、calloc 或 realloc。
释放栈变量的地址、字符串字面量,或指向堆块中间位置的指针,都会导致未定义行为。
int x = 5;
/* free(&x); WRONG: x is on the stack */
int *p = malloc(sizeof(int));
free(p); /* correct */提前返回导致的泄漏
一种常见的泄漏情况是:您分配了内存,随后进入错误处理路径,在释放之前就返回了。这样一来,堆块就丢失了。
请确保每条负责这块内存的退出路径都会先释放它。
int *a = malloc(n * sizeof(*a));
if (something_failed) {
free(a); /* don't forget this before returning */
return -1;
}干净地分配和释放内存的程序
这个程序会在每条路径上分配、使用并释放内存,不会产生任何泄漏。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 4;
int *a = malloc(n * sizeof(*a));
if (!a) return 1;
for (int i = 0; i < n; i++) a[i] = i + 1;
int sum = 0;
for (int i = 0; i < n; i++) sum += a[i];
printf("%d\n", sum);
free(a);
a = NULL;
return 0;
}释放嵌套分配
如果一个堆块中包含指向其他堆块的指针,请先释放内部堆块,再释放外部堆块。
如果先释放外部堆块,就会丢失内部堆块的地址,从而导致它们泄漏。
for (size_t i = 0; i < rows; i++)
free(grid[i]); /* free each row first */
free(grid); /* then the array of pointers */每个堆块只有一个所有者
请确定代码中的哪一部分拥有每次分配得到的内存,并负责释放它。
如果两个指针指向同一个堆块并且都释放它,就会发生重复释放。明确所有权可以避免这种问题。
使用工具检测泄漏
您不必靠肉眼查找泄漏。valgrind 或 AddressSanitizer 等工具可以报告泄漏和无效释放,并指出对应的行号。
请使用 -g 进行编译,然后在该工具下运行程序,以准确查看哪些内存没有被释放。
/* gcc -g -fsanitize=address prog.c && ./a.out */
/* or: valgrind --leak-check=full ./a.out */按设置顺序的相反顺序释放
一个可靠的习惯是:在获取多个资源的函数中,按照获取顺序的相反顺序释放它们。
这与构建依赖关系的方式相对应,也能让清理过程更加可预测。
char *buf = malloc(64);
int *idx = malloc(64 * sizeof(int));
/* ... use them ... */
free(idx); /* free last-acquired first */
free(buf);快速检查
请测试您对释放内存的理解。
回顾
请在每条代码路径上为每次内存分配恰好配对一次 free。
释放后将指针设为 NULL,可以避免悬空指针和重复释放。请先释放嵌套分配的内部对象,为每个堆块指定一个所有者,并使用 valgrind 或地址消毒器捕获泄漏。现在,您已经掌握了完整的动态数组工具集。
用 AI 导师学习 C — 免费
在浏览器中编写并运行真实代码,获得全天候 AI 导师的即时帮助,并在网页或应用中继续学习。
- 课程
- 39
- 课程
- 144
常见问题解答
「释放内存并避免泄漏」课时是免费的吗?
是的 — 「释放内存并避免泄漏」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「释放内存并避免泄漏」这节课中我会学到什么?
正确地清理资源。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「释放内存并避免泄漏」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 分配数组
- 使用 realloc 扩展
- 可复用的向量类型
- 释放内存并避免泄漏