【问题标题】:What this 4K difference?这4K有什么区别?
【发布时间】:2013-10-25 23:48:07
【问题描述】:

我为一个简单的测试编写了一个简单的代码。

#include <stdio.h>

typedef struct
{
    void* Data;
}List;

void x()
{
    getchar();

    int i;
    List* myList[100000];

    for(i = 0; i < 100000; i++)
    {
        myList[i] = (List*)malloc(sizeof(List)*1024*1024);
    }

    getchar();

    for(i = 0; i < 100000; i++)
    {
        free(myList[i]);
    }
}

int main()
{
    x();
    getchar();
    return 0;
}

我在“taskmgr”中看过程序,我看过: - 540K - 4.500K - 544K(4K 有什么区别?)

【问题讨论】:

  • 它依赖于实现,您还没有告诉我们您使用的是什么实现。但无论如何,最好忽略这一点并继续前进——当然 4KB 根本不重要。

标签: c memory memory-leaks heap-memory


【解决方案1】:

如果您的所有分配都成功,您将使用大约 100000 * 1024 * 1024 * sizeof (List) 字节,即(假设 List 是 4 字节,32 位指针)略高于 390 GB。。 p>

由于您引用的数字要低得多,因此可以放心地假设并非所有分配都真正成功。实际上,很难想象它们都在 32 位系统上成功......无论如何,你的代码从不检查这个,所以很难说。

教训:malloc() 可能会失败,如果不检查返回值就不能假设分配成功。

另外,don't cast the return value of malloc() in C

【讨论】:

  • 另一个重要的一点是malloc()可以成功。即使您分配的 RAM 比系统实际拥有的 RAM 多一百倍。然后在您尝试使用它们之前不实际提交页面。 (不过,我不知道 Windos 是否这样做。)
【解决方案2】:

现代操作系统倾向于过度使用资源,并且仅在您使用资源时才实际执行分配。这是使用分页和页面错误为内存完成的。由于您从未读取或写入您通过 malloc() 请求的内存,因此操作系统很可能从未映射任何页面。

尝试写入到每个分配的缓冲区。读取可能还不够,因为可以映射系统或进程范围的零页并依靠 Copy On Write (COW) 来执行实际分配。这种情况经常发生。

即使这样,如果您为每个缓冲区分配的页面长度超过了页面的长度,您可能需要执行 per-page 写入才能真正获取所有页面。

这样做并观察你的过程变得越来越胖。

【讨论】:

  • 只是一个半相关的问题。这个“零页面”的概念实际上来自哪里?我已经看过许多操作系统的 VM 代码,我已经在其中一些上工作过,但我从来没有见过这样的实现,从来没有看到它的意义(由于很多原因,它可能非常低效)和除了人们在互联网上谈论它之外,甚至从未在文学作品中看到过它。最接近零页面是为了简化在各种类 unix 系统上读取 /dev/zero 的实现(但它与 /dev/zero 的 mmap 无关,不要混淆)。
  • 这是一种优化,使操作系统能够快速提供零页面,例如,替换memset(..., 0) 调用或加载程序二进制文件的 BSS 段时。此外,如果您检查一下,您可能会注意到 Linux 提供给您的大多数新内存(例如通过malloc())都被归零,因为最容易映射零页面并稍后通过 COW 实际执行分配。您还可以在 Linux 源代码中找到对这个概念的引用。
  • 这不是优化。这是任何现代机器上的次优化,因为当您执行 calloc->read->write 或类似的操作(或就此而言读取 BSS)时 TLB 失效成本,这并不少见。我看你是对的。至少在早期的 linux 2.6 中他们曾经做过这样疯狂的事情,但他们似乎不再这样做了,至少不是以明显的方式,现在至少我知道这个概念来自哪里并且我的好奇心得到了满足。跨度>
猜你喜欢
  • 2020-06-28
  • 1970-01-01
  • 2011-04-06
  • 2013-01-16
  • 1970-01-01
  • 2018-08-25
  • 2012-09-27
  • 2012-06-12
相关资源
最近更新 更多