9
回答
free释放内存为什么要把内存中的内容删除
利用AWS快速构建适用于生产的无服务器应用程序,免费试用12个月>>>   

遇到一题面试题,回来想了好久,没有得出答案。

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

int main()
{
    char *p = (char *)malloc(100);
    memcpy( p,"hello",6 );

    printf( "%s--%p\n",p,p );

    free( p );

    printf( "%s--%p\n",p,p );

    memcpy( p,"hello",6 );

    printf( "%s--%p\n",p,p );

    return 0;
}
输出结果

hello--0x23ec010
--0x23ec010
hello--0x23ec010

可以看到,在free后,p指向的内存内容没有显示出来,用GDB查看内存也确实都为0了。而free应该是不会把内存中的内容清0才对,那为什么会变0呢。这不是偶尔,换过系统,换过new/delete都是同样的情况。

按我的理解,free之后,内存有几种情况:

1.被glibc的内存分配策划返还给系统,即程序不再持有该内存

2.仍有程序持有,放到fastbin之类的待用

3.已被重新分配

首先,程序很简单,占用内存不多,glibc应该不会归还。程序没有再分配内存(在free之后,printf之前打的断点)。而且后来强制使用该内存也是可以的,说明处于第二种情况。

求解:为什么free后p所指向的内容不是hello

<无标签>
举报
changnet
发帖于3年前 9回/1K+阅
共有9个答案 最后回答: 3年前

既然清零了,我认为是free接口内部实现的. 在C Runtime 运行时,会通过系统调用接口(Windows下是Win32 API),获取一部分内存空间供标准C的内存管理模块(malloc/free)使用,当剩下的空间不足或你的malloc size参数太大的时候,他才会继续通过系统调用接口再申请新的内存空间进行扩展,以备使用. 

那么既然Free之后为0了,应该是为了安全, Glibc 的说明在下面这个链接:

https://www.gnu.org/software/libc/manual/html_mono/libc.html#Freeing-after-Malloc

真想要知道为什么,就看看glibc的源码:

在glibc的malloc目录下malloc.c中

_int_free 有调用下面这个函数,

static void
free_perturb (char *p, size_t n)
{
  if (__glibc_unlikely (perturb_byte))
    memset (p, perturb_byte, n);
}

找到这个变量perturb_byte的值,就应该清楚了.

楼主,请教你的事情啊。动态分配的内存是操作系统分配的还是glibc分配的?哈。至于其他的不要在意。相反你所要在意的是,每次free(p)后,要将p清零。


free掉的内存是不可预知,所以清0也正常,不清0也正常。一般的视gcc的编译参数,表现行为不一样。如果是调试版本,即没有定义NDEBUG,则会清0,这是为了更好的暴露问题。如果是生产版本,编译时定义了宏NDEBUG,则为了性能不会清0操作。

希望对你有用。

.ident  "GCC: (Debian 4.7.2-5) 4.7.2" glibc 2.0输出:

hello--0xa01e6a8
hello--0xa01e6a8
hello--0xa01e6a8

free只是从链表里摘掉,实现上不会清0这么无聊吧。楼主什么环境的运行结果。




p的地址是虚拟地址,free掉后不能保证原地址还可用,再执行输出的话可能是原值、0、其他值、崩溃等等

一般不会做自动清零这种事情,很好奇楼主用的什么系统。但是可以肯定这种行为不是C标准中规定的,对于以下情形,需要手动清零再释放:

1. 存储在内存中的密钥

2. 用户输入的口令

3. 存储在内存中的隐私数据(硬盘上没有相同形式)

这个主要是为了防止入侵者对用户电脑的内存进行热拷贝或分析的行为。

--- 共有 3 条评论 ---
此号作废回复 @汤医森 : Thx ^_^ 3年前 回复
汤医森回复 @小猫嘿嘿哈 : 清零再释放,不是释放再清零 3年前 回复
此号作废free完了再memset手动清的话,编译时会被优化掉吧? 3年前 回复

引用来自“棋有此理”的评论

既然清零了,我认为是free接口内部实现的. 在C Runtime 运行时,会通过系统调用接口(Windows下是Win32 API),获取一部分内存空间供标准C的内存管理模块(malloc/free)使用,当剩下的空间不足或你的malloc size参数太大的时候,他才会继续通过系统调用接口再申请新的内存空间进行扩展,以备使用. 

那么既然Free之后为0了,应该是为了安全, Glibc 的说明在下面这个链接:

https://www.gnu.org/software/libc/manual/html_mono/libc.html#Freeing-after-Malloc

真想要知道为什么,就看看glibc的源码:

在glibc的malloc目录下malloc.c中

_int_free 有调用下面这个函数,

static void
free_perturb (char *p, size_t n)
{
  if (__glibc_unlikely (perturb_byte))
    memset (p, perturb_byte, n);
}

找到这个变量perturb_byte的值,就应该清楚了.

 确实是这样。

另外,上面几位的回答也提供了很大帮助。

在debian下,是不回清零的。

GNU C Library (Debian EGLIBC 2.11.3-4) stable release version 2.11.3, by Roland McGrath et al.
Copyright (C) 2009 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.4.5.
Compiled on a Linux 2.6.32 system on 2012-06-08.
Available extensions:
        crypt add-on version 2.1 by Michael Glad and others
        GNU Libidn by Simon Josefsson
        Native POSIX Threads Library by Ulrich Drepper et al
        BIND-8.2.3-T5B
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.
而在ubuntu 14.04下,无论是debug版本还是release版本,即使把gcc的优化加到o3,也是会清零的。GDB的的内存断点如下:

(gdb) p p
$1 = 0x602010 "hello"
(gdb) p/x *0x602010@10
$3 = {0x6c6c6568, 0x6f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}
(gdb) x/10w 0x602010
0x602010: 0x6c6c6568 0x0000006f 0x00000000 0x00000000
0x602020: 0x00000000 0x00000000 0x00000000 0x00000000
0x602030: 0x00000000 0x00000000
(gdb) watch *(int *)0x602010
Hardware watchpoint 2: *(int *)0x602010
(gdb) c
Continuing.
Hardware watchpoint 2: *(int *)0x602010


Old value = 1819043176
New value = 0
_int_free (av=0x7ffff7dd3760 <main_arena>, p=0x602000, have_lock=0)
    at malloc.c:3920
3920 malloc.c: No such file or directory.
其中,0x6c6c6568, 0x6f就是16进制的hello,在_int_free中被重置0.

ubuntu 14.04的glibc版本如下:

GNU C Library (Ubuntu EGLIBC 2.19-0ubuntu6.6) stable release version 2.19, by Roland McGrath et al.
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.13.11 system on 2015-02-25.
Available extensions:
crypt add-on version 2.1 by Michael Glad and others
GNU Libidn by Simon Josefsson
Native POSIX Threads Library by Ulrich Drepper et al
BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/eglibc/+bugs>.


顶部