You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言free释放内存后访问未崩溃、重复free触发报错问题

核心结论:未定义行为不保证触发崩溃

你的理解存在偏差:C语言中访问已释放内存、重复释放内存都属于未定义行为(Undefined Behavior, UB),语言规范从来没有要求这类场景必须触发程序崩溃,"运行正常输出正确结果"本身就是未定义行为的合法表现之一。

为什么单次free后访问悬垂指针没有崩溃

free()的实际行为和你预期的差异非常大:

  • 它的核心作用是把malloc分配的内存块标记为「空闲可复用」,交还给进程内部的堆管理器维护,既不会主动擦除内存里存的原有数据,也不会把这块内存从进程的可访问地址空间里移除,更不会自动把指针p改成空指针。
  • 你的测试场景里,刚释放完内存立刻调用print_point访问,中间没有其他代码申请内存、覆盖这块空闲块的内容,之前写入的x=100、y=300还完整存在内存里;同时这块内存属于进程已经拿到使用权的堆地址范围,CPU访问时不会触发权限错误,所以程序看起来"正常运行"。
  • 这种"正常"完全是巧合,没有任何可靠性:换个编译器版本、开个编译优化、在free和访问之间加几行其他内存操作,就可能出现读到乱码、程序崩溃、甚至悄悄篡改其他变量值的问题,结果完全不可预测。
  • 只有访问的地址属于进程未申请的地址空间、或者没有对应读写权限时,才会必然触发段错误,刚释放的小块堆内存显然不满足这个条件。

第一版测试代码如下:

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

void print_point(Point *p) {
    printf("Point { x = %i, y = %i }", p->x, p->y);
}

int main() {
    Point *p = malloc(sizeof(Point));

    p->x = 100;
    p->y = 300;

    free(p);

    print_point(p);

    return 0;
}

为什么double free后会触发错误

第二版代码里两次释放同一块内存触发错误,和访问悬垂指针的逻辑完全不同:

  • 主流堆管理器(比如Linux下glibc的ptmalloc、通用场景常用的jemalloc)都内置了基础的堆损坏检测逻辑,重复释放同一块内存会直接破坏堆维护空闲块的元数据,堆管理器一旦检测到这类损坏,会主动中止进程,抛出类似double free or corruption (top)的报错——这个错误是堆管理器主动触发的,不是硬件层面的内存访问权限错误。
  • 重复释放后堆结构已经处于损坏状态,后续再访问对应地址的内存,触发异常的概率会大幅升高,但这同样不是必然结果:如果堆管理器关闭了检测、或者损坏的元数据没被校验到,程序可能不会立刻报错,而是留下更隐蔽的内存安全漏洞。

第二版测试代码如下:

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    int x;
    int y;
} Point;

void print_point(Point *p) {
    printf("Point { x = %i, y = %i }", p->x, p->y);
}

int main() {
    Point *p = malloc(sizeof(Point));

    p->x = 100;
    p->y = 300;

    Point *p2 = p;

    free(p);
    free(p2);

    print_point(p);

    return 0;
}

实操提醒

  • 绝对不要把"程序跑起来没崩溃"当成内存操作正确的判断依据,所有未定义行为的表现都是不可预测的,很多内存bug会潜伏很久才在生产环境触发。
  • 养成正确的内存操作习惯:执行free()之后立刻把对应指针置为NULL,从根源上避免后续意外访问悬垂指针;严格保证每一块malloc分配的内存只被free一次。

内容的提问来源于stack exchange,提问作者Кирилл Леушкин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:12:22