【问题标题】:Is the memory chunk returned by malloc (and its cousins) initialized to Zero?malloc(及其表兄弟)返回的内存块是否初始化为零?
【发布时间】:2015-05-07 01:47:51
【问题描述】:

我写了一个代码来测试Linux和Windows操作系统的内存管理压力测试。为了进一步测试,我继续检查了 malloc() 返回的内存中存在哪些值。

返回的值都是 0(零)。我已经阅读了 malloc 的手册页,在 Windows 和 Linux 上都进行了检查,但我 不能找出这种行为的原因。根据手册页的

malloc() 函数分配 size 字节并返回一个指向已分配内存的指针。内存未初始化。

要清除内存段,必须手动使用 memset()。

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

int eat(long total,int chunk){
    long i;
    for(i=0;i<total;i+=chunk){
        short *buffer=malloc(sizeof(char)*chunk);     
        if(buffer==NULL){
            return -1;
        }
        printf("\nDATA=%d",*buffer);
        memset(buffer,0,chunk);
    }
    return 0;
}

int main(int argc, char *argv[]){
    int i,chunk=1024;
    long size=10000;
            printf("Got %ld bytes in chunks of %d...\n",size,chunk);
            if(eat(size,chunk)==0){
                printf("Done, press any key to free the memory\n");
                getchar();
            }else{
                printf("ERROR: Could not allocate the memory");
            }
        }

也许我错过了什么。 代码改编自here

编辑: GCC 特定输出的问题已得到回答here。我相信 Windows 操作系统也会遵循相同的程序。

【问题讨论】:

    标签: c linux memory memory-management malloc


    【解决方案1】:

    malloc()返回的内存没有初始化,也就是说它可能是任何东西。它可能为零,也可能不是; '未初始化' 表示它可以是任何东西(包括零)。要获得保证归零的页面,请使用calloc()

    您看到归零页面(无论如何在 Linux 上)的原因是,如果应用程序请求新页面,这些页面会被操作系统归零(或者更准确地说,它们是已知零的固定页面的写时复制图像作为“全局零页面”)。但是如果malloc() 碰巧使用了已经分配给应用程序的内存,该应用程序已经被释放(而不是扩展堆),您很可能会看到非零数据。请注意,操作系统提供的页面归零是操作系统特定的特征(主要是为了安全,这样一个进程不会以恰好具有来自另一个进程的数据的页面结束),并且不是 C 标准强制要求的。

    您要求source 将页面归零:get_free_page 表示 'get_free_page() 采用一个参数,一个优先级。 ...它从free_page_list 中取出一个页面,更新mem_map将页面归零并返回页面的物理地址。' Here 的另一个帖子这很好地解释了它,也解释了为什么使用calloc()malloc()+memset() 更好。

    请注意,您并没有检查整个分配的块是否为零。你想要这样的东西(未经测试):

    int n;
    char nonzero=0;
    char *buffer=malloc(sizeof(char)*chunk);     
    if(buffer==NULL){
        return -1;
    }
    for (n = 0; n<chunk; n++)
        nonzero = nonzero || buffer[n];  
    printf("\nDATA=%s\n",nonzero?"nonzero":"zero");
    

    【讨论】:

    • 感谢您的解释。您能否就“这些页面被操作系统归零”这一点分享一些参考资料。谢谢
    • @GradyPlayer 今天使用了太多的语言。固定的。虽然|= 也可以。
    • 感谢您的参考。
    【解决方案2】:

    你说的很对; C 语言标准不保证这种行为。

    您所观察到的可能只是偶然(您只检查了每次分配中的几个字节),也可能是您的操作系统和 C 运行时库如何分配内存的产物。

    【讨论】:

    • 感谢@Oliver 的澄清,但是手册页说该块未初始化,但我得到的块已初始化。操作系统是否在进行初始化?
    • 没有人说禁止返回已设置为某个值的内存...但不能保证,如果您依赖它,可能会在其他系统上失败
    【解决方案3】:

    有了这个声明:

    printf("\nDATA=%d",*buffer);
    

    您只检查刚刚被 malloc()'ed 的第一个 sizeof(short) 字节数(通常是两 (2) 个字节)。

    此外,第一次你可能会幸运地得到全零,但在你的程序执行(并使用)堆内存之后,contents-after-malloc() 将是未定义的。

    【讨论】:

      【解决方案4】:

      内存分配函数:calloc() 将返回一个指向'新区域的指针并将所有字节设置为零。

      内存分配函数:realloc() 将返回一个指向(可能是新的)区域的指针,并从旧区域复制字节。新区域将是“新”请求的长度

      内存分配函数 malloc 将返回一个指向新区域的指针,但不会将字节设置为任何特定值

      【讨论】:

        【解决方案5】:

        返回的值都是 0(零)。

        但这并不能保证。这是因为你只是在运行你的程序。如果您经常使用 malloc、随机填充和释放,您会开始注意到之前释放的内存正在被重用,因此您将开始在 malloc 中获得非零块。

        【讨论】:

          【解决方案6】:

          是的,你是对的 malloc() 不会将值初始化为零。它任意地从堆中提取它被告知分配的内存量,这实际上意味着其中可能已经存储了任何东西。因此,您应该只在您确定要将其设置为一个值的情况下使用 malloc()。如果您要立即使用它进行算术运算,您可能会得到一些可疑的结果(我已经多次亲身体验过;您将拥有有时疯狂输出的功能代码)。

          因此,使用 memset() 将您未设置的值设置为零。或者我的建议是使用calloc()。除了 malloc,Calloc 对值进行零初始化。并且据我所知,它比 malloc() 和 memset() 的组合更快,另一方面 malloc 比 calloc 更快。因此,请尽量在问题点找到最快的版本,保持您的记忆形式。

          还可以在这里查看此帖子:MPI matrix-vector-multiplication returns sometimes correct sometimes weird values。问题不同,但原因相同。

          【讨论】:

            猜你喜欢
            • 2012-06-19
            • 1970-01-01
            • 2021-10-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-06
            • 2015-06-28
            • 2021-04-05
            相关资源
            最近更新 更多