【问题标题】:Malloc & calloc: different memory size allocatedMalloc & calloc:分配不同的内存大小
【发布时间】:2015-12-01 14:55:18
【问题描述】:

所以,我有这段代码:

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

int main()
{
    char *p;
    long n = 1;

    while(1) {
        p = malloc(n * sizeof(char));
        //p = calloc(n, sizeof(char));

        if(p) {
            printf("[%ld] Memory allocation successful! Address: %p\n", n , p);
            n++;
         } else {
            printf("No more memory! Sorry...");
            break;
        }
    }

    free(p);
    getch();
    return 0;
}

我在 Windows 上运行。有趣的事:

  • 如果我们使用 malloc,程序会分配大约 430 MB 的内存然后停止(这里的照片 => http://i.imgur.com/woswThG.png

  • 如果我们使用 calloc,程序会分配大约 2 GB 的内存然后停止(这里的照片 => http://i.imgur.com/3JKy5pA.png

  • (奇怪的测试):如果我们同时使用它们,它最多使用 (~400MB + ~2GB) / 2 => ~1.2GB

但是,如果我在 Linux 上运行相同的代码,分配会继续进行(在 600k 分配和使用了许多 GB 之后,它仍然会继续,直到最终被杀死)并且使用的内存量大致相同。

所以我的问题是:他们不应该分配相同数量的内存吗?我认为唯一的区别是 calloc 用零初始化内存(malloc 返回未初始化的内存)。为什么它只发生在 Windows 上?它既奇怪又有趣。

希望你能帮我解释一下。谢谢!

编辑:

  • Code::Blocks 13.12 与 GNU GCC 编译器

  • Windows 10 (x64)

  • Linux Mint 17.2 “Rafaela” - Cinnamon(64 位)(用于 Linux 测试)

【问题讨论】:

  • 分配的virtual内存和分配的physical内存之间存在差异...以及两个操作系统如何处理和显示之间的差异,例如内存分配。
  • 这样的测试有什么实际用途?
  • 我们在大学的编程课程中学习内存分配,我只是想看看一切是如何工作的。我写这个程序只是为了看看我的内存填得有多快(我有 8GB 内存,但在 Windows 中,这个程序使用了最大 2GB - 我注意到的另一件事)。
  • 您应该更准确地了解环境:哪个编译器? 32 位还是 64 位?哪个版本的 Windows 和 Linux...
  • 尝试在malloc之后添加memset(p,0, n)。然后你应该得到与calloc 版本相同的结果。 calloc 清除分配的内存,但 malloc 不会。

标签: c memory memory-management malloc calloc


【解决方案1】:

查看程序输出,您实际上分配了相同数量的块,65188malloc65189calloc。忽略开销,这略小于 2GB 的内存。

我的猜测是您在 32 位模式下编译(指针被转储为 32 位),这将单个用户进程可用的内存量限制为小于 2GB。进程图显示的不同在于你的程序如何使用它分配的内存。

malloc 版本没有触及分配的页面:超过四分之三的页面实际上没有被映射,因此 只有 430MB。

calloc 版本显示 2GB 的 映射 内存:您的 C 库函数 calloc 可能会清除分配的内存,即使是从操作系统获得的页面也是如此。这不是最佳的,但只有在您不触摸分配的内存时才可见,无论如何都是一种特殊情况。然而,不清除从操作系统获得的页面会更快,因为它们被指定为零填充。

在 Linux 中,您可能正在编译为 64 位,从而可以访问超过 2GB 的虚拟进程空间。由于您不接触内存,因此它没有被映射,calloc 的情况似乎也发生了同样的情况。 C 运行时不同(Linux 上为 64 位 glibc,Windows 上为 32 位 Microsoft Library)。您应该在 Linux 的不同终端中使用 topps 来检查在这两种情况下实际映射到您的进程的内存量。

【讨论】:

  • calloc 绝对零填充分配的内存,而 malloc 不会。
  • @MichaelWalz 在 Linux 上,calloc 不会强制分配物理内存 - 只要不触及它,它就会保持虚拟状态。就像malloc。大约几周前进行了精确测试。
  • @Dummy00001 奇怪,calloc 的许多文档包括 this one 声明 calloc 零填充分配的内存。
  • 感谢您的回答!我在 32 位模式下编译,所以我会尝试在 64 位模式下编译代码,看看发生了什么。其余的解释很好:)祝你有美好的一天!
  • @MichaelWalz,是的,正如@chqrlie 所解释的那样。 C标准是可移植的,没有虚拟内存的概念。操作系统如何选择“填充”或“初始化”内存,与标准无关。多年前,Linux/glibc 在calloced 内存上使用正常的memset()(这会强制分配物理内存)——但今天他们已经对其进行了优化以跳过memset()
猜你喜欢
  • 1970-01-01
  • 2014-02-15
  • 1970-01-01
  • 2016-02-13
  • 2020-11-26
  • 2021-01-26
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
相关资源
最近更新 更多