猿问

为什么malloc在GCC中将值初始化为0?

为什么malloc在GCC中将值初始化为0?

也许不同的平台是不同的,但是

当我使用GCC编译并运行下面的代码时,我每次在ubuntu11.10中都得到0。

#include <stdio.h>#include <stdlib.h>int main(){
    double *a = (double*) malloc(sizeof(double)*100)
    printf("%f", *a);}

为什么即使有calloc,malloc也是这样的呢?

这不意味着仅仅将值初始化为0就会产生不必要的性能开销,即使有时不希望这样做?


编辑:哦,我前面的例子不是初始化,而是碰巧使用了“新鲜”块。

确切地说,我要找的是为什么它在分配一个大块时初始化它:

int main(){
    int *a = (int*) malloc(sizeof(int)*200000);
    a[10] = 3;
    printf("%d", *(a+10));

    free(a);

    a = (double*) malloc(sizeof(double)*200000);
    printf("%d", *(a+10));}OUTPUT: 3
        0 (initialized)

但是,谢谢你指出,有一个安全的原因时,错位!(从未想过)。确保在分配新块或大块时必须将其初始化为零。


一只甜甜圈
浏览 1186回答 3
3回答

Cats萌萌

操作系统通常会清除它发送给进程的新内存页,这样它就不能查看旧进程的数据。这意味着当您第一次初始化变量(或malloc之类的东西)时,它通常是零,但是如果您曾经重用该内存(例如,通过释放它和再次释放malloc-ing),那么所有的赌注都会停止。这种不一致正是为什么未初始化的变量很难找到bug的原因。至于不必要的表演间接费用,避免未指明的行为可能更重要。..无论在这种情况下你能获得什么小小的性能提升,如果有人稍微修改了代码(打破了以前的假设)或将其移植到另一个系统(假设最初可能是无效的),那么很难找到您必须处理的bug。

湖上湖

你为什么认为malloc()初始化为零?恰巧第一次打电话到malloc()结果打电话给sbrk或mmap系统调用,它从操作系统分配一页内存。由于安全原因,操作系统必须提供零初始化内存(否则,来自其他进程的数据就会可见!)所以你可能会认为-操作系统浪费时间对页面进行归零。但是没有!在linux中,有一个特殊的系统范围内的单例页面,名为“零页”,该页面将被映射为“复制即写”,这意味着只有当您实际在该页上写入时,操作系统才会分配另一页并初始化它。所以我希望这能回答你关于表现的问题。内存分页模型允许对内存的使用进行排序-通过支持同一页的多个映射的能力,加上在第一次写入发生时处理这种情况的能力。如果你打电话free(),glibc分配器将该区域返回到它的空闲列表,并且当malloc()再次调用时,您可能会得到相同的区域,但与前面的数据不兼容。最终,free()可能通过再次调用系统调用将内存返回到操作系统。注意,glibc&nbsp;手册页在……上面malloc()严格地说内存没有被清除,所以根据API上的“约定”,您不能假设它确实被清除了。这是最初的节选:malloc()分配大小字节并返回指向分配内存的指针。内存没有清除。如果大小为0,那么malloc()将返回NULL,或者返回一个以后可以成功传递给Free()的唯一指针值。如果您愿意,如果您担心性能或其他副作用,可以阅读更多关于该文档的内容。

莫回无

简短答覆:没有,只是碰巧在你的情况下是零。(此外,您的测试用例没有显示数据为零。它只显示一个元素为零的情况。)详细答覆:当你打电话malloc()会发生两件事之一:它回收以前分配并从同一进程中释放的内存。它从操作系统请求新页面。在第一种情况下,内存将包含以前分配的剩余数据。所以不会是零。这是执行少量分配时的通常情况。在第二种情况下,内存将来自操作系统。当程序内存耗尽时,或者当您请求一个非常大的分配时,就会发生这种情况。(与您的示例中的情况一样)以下是问题所在:来自操作系统的内存将被归零保安理由*当操作系统给您内存时,它可以从不同的进程中释放出来。以便内存可以包含敏感信息,如密码。因此,为了防止您读取这些数据,操作系统将在将其提供给您之前将其归零。*我注意到C标准对此没有任何规定。这是严格意义上的OS行为。因此,这种零化可能存在,也可能不存在于安全性不受关注的系统上。为了给这方面提供更多的性能背景:正如@R.在注释中提到的,这个零化是为什么您应该始终使用calloc()而不是malloc() + memset(). calloc()可以利用这一事实来避免单独的memset().另一方面,这种归零有时是性能瓶颈。在一些数值应用中(例如格格不入的FFT),您需要分配一大块划痕内存。使用它来执行任何算法,然后释放它。在这些情况下,零化是不必要的,相当于纯粹的开销。我所见过的最极端的例子是20秒的零开销,这是一个70秒操作的零开销,它有一个48 GB的划痕缓冲区。(大约30%的间接费用。)(诚然:这台机器确实缺乏内存带宽。)显而易见的解决方案是简单地手动重用内存。但这往往需要突破已建立的接口。(特别是如果它是库例程的一部分)
随时随地看视频慕课网APP
我要回答