首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  C/C++/Obj-C

最近看 Linux 内核,看到一个问题: malloc 申请的内存,指针为 prt, free 之后如果没有赋值 prt=NULL 会如何?

  •  
  •   wind3110991 · 2015-04-05 02:28:16 +08:00 · 985 次点击
    这是一个创建于 1596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    例如:
    在堆段中手动malloc申请一段内存:
    char* ptr = (char*)malloc(10);
    ........
    free(ptr);
    //ptr = NULL;假设这步忘记做了

    那么这个ptr指针是不是依然指向那一块内存?
    也就是说我接下来下次依然可以使用ptr指针?
    貌似free的内存块是要够一页大小才会置换页面的
    请问这个ptr如果没有赋值NULL会有什么后果?

    另外,那么问题又来了
    如果我双重释放ptr又会如何?
    free(ptr);
    free(ptr);

    21 回复  |  直到 2015-05-30 17:01:11 +08:00
        1
    ryd994   2015-04-05 03:05:24 +08:00   ♥ 1
    依然指向
    用的话可能segfault
    重复free的话会segfault
    赋值null就是为了避免重复free
    free NULL是安全的
        2
    ncisoft   2015-04-05 03:17:11 +08:00 via iPad
    有这闲功夫发帖,都够写段代码测试下了,差评
        3
    RobberPhex   2015-04-05 11:17:17 +08:00   ♥ 1
    glibc是不允许多次free的,会出现异常:`Error in './a.out': double free or corruption`

    另外,free小块内存后是可以访问的,因为那块内存还是被glibc管理的,不过这会破坏glibc的内存管理机制。

    不过,释放大块内存的时候,glibc会将其归还给操作系统,此时访问会导致段错误。
    //我猜测:mmap分配的内存,释放时会直接归还操作系统;brk/sbrk在顶端释放大量内存时会归还。
        4
    wind3110991   2015-04-05 12:21:34 +08:00
    @ncisoft 谢谢
        5
    wind3110991   2015-04-05 12:30:57 +08:00
    @RobberPhex 就是说free的对象要看是大还是小吧?谢谢你!你解答了我之前的一个问题,就是free之后的内存会不会马上归还给os
        6
    phoeagon   2015-04-05 12:35:48 +08:00 via Android
    @wind3110991 还不还是implementation specific,不是标准定的,不要依赖编译器这种随时能改的实现
        7
    wind3110991   2015-04-05 16:06:25 +08:00
    @phoeagon = =不太理解,就是说还是要以内核工作机制为准吗
        8
    msg7086   2015-04-05 16:36:16 +08:00   ♥ 2
    @wind3110991 就是说,一旦free了,这块内存就不属于你了。
    接下来的访问就相当于偷着用,抓到就segfault,没抓到就是凑巧。
    就像你租房期满,钥匙还给了房东。
    接下来你再拿偷配的钥匙访问房子就可能会被抓。
        9
    gamexg   2015-04-05 22:11:12 +08:00
    还有可能破化程序的其他部分。

    你已经 free 了,其他代码 malloc 时有可能分配到相同位置,然后保存数据。
        10
    jedihy   2015-04-05 23:15:03 +08:00 via iPhone
    因为后面用这个变量了吧,节省一条指令
        11
    wind3110991   2015-04-07 00:30:05 +08:00
    @gamexg 谢啦~~我明白啦
        12
    khan   2015-04-30 10:43:43 +08:00
    因为有很多地方都是这样判断

    if (ptr == NULL) {
    ...do something
    }

    你如果不置空, 后面打算怎么复用.


    free(ptr);
    ptr = NULL; //如果不打算复用指针, 这行代码意义不大. 也没有危险或潜在威胁

    所以这种代码 称之为防御性代码.
        13
    khan   2015-04-30 10:49:50 +08:00
    @RobberPhex: 你说的内容有俩疑点
    1. c++ 中我知道有new alloc 内存复用机制, 可以由 stdlib 来管理代码分配的内存.
    但是 c 中的 alloc 就真的是直接调用系统的内存管理模块了. 应该不存在你说的 libc 管理内存的可能性.

    2. mmap 是内存镜像文件. 我记得没错的话是处理超大型文件时不载入内存的一种实现方式. 直接用磁盘I/O来进行文件操作. 大文件载入内存导致爆内存的问题. 所以 mmap 本身应该可以认为是不占用内存的.

    错漏之处还望斧正.
        14
    RobberPhex   2015-04-30 12:36:05 +08:00   ♥ 1
    @khan malloc是libc提供的,在glibc的实现中,是有glibc自己的内存池的。另外,alloc应该也是libc提供的功能,但是linux没有这个内存调用;只有brk调用。

    至于mmap,glibc在分配大块内存时也会用到,在逻辑上占用了内存,但是实际上在读写后,发生缺页中断后才会真正分配。
        15
    khan   2015-04-30 13:58:24 +08:00
    @ryd994 这种情况其实称之为野指针. 情况不可预估. 可能你会发现某个堆的数据突然变化了. 从而导致各种灵异现象.
    另外如果 = NULL, 是空指针, 和内核地址重叠. 如果强制访问. 持有进程会被内核杀死.
        16
    ryd994   2015-04-30 14:05:32 +08:00   ♥ 1
    @khan 所以我说可能Segfault。主要看这个地址是否还属于这个进程。
    访问空指针当然是要死,但是free是可以的。
        17
    khan   2015-04-30 15:00:16 +08:00
    @ryd994 32bit 保护地址模式早就没有远程指针的概念了. 无法访问不属于本进程的地址吧
        18
    ryd994   2015-04-30 15:04:38 +08:00   ♥ 2
    @khan 是的
    所以如果运气好,尽管调用了系统调用,申请释放,但系统还没有释放(有性能因素不是立刻释放),那么地址还属于这个进程,则会出现访问混乱。
    如果操作系统已经释放了内存,就会segfault
        19
    khan   2015-04-30 15:09:44 +08:00
    @ryd994 在@RobberPhex的提示下, 正在看Ptmalloc2的 Free 部分实现. 证实了你的说法.
        20
    qiuyi116   2015-05-27 22:55:42 +08:00
    free但是不给赋NULL就是自己挖坑,,亲测啊。。因为free知识把ptr指向的内存资源释放归还给了OS,但是呢,ptr还是指向这个虚拟地址的啊。访问ptr的值就会Segmentfault.....
        21
    wind3110991   2015-05-30 17:01:11 +08:00
    嗯嗯,我也测试过,如果没有赋值ptr = NULL
    之后还是会保留ptr指向的虚拟地址
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1069 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 23ms · UTC 23:42 · PVG 07:42 · LAX 16:42 · JFK 19:42
    ♥ Do have faith in what you're doing.