【问题标题】:malloc() in C And Memory UsageC 和内存使用中的 malloc()
【发布时间】:2012-03-09 00:55:53
【问题描述】:

我正在尝试使用 malloc 进行实验,看看是否可以分配所有可用内存。

我使用了以下简单的程序并有几个问题:

int main(void)
{
    char * ptr;
    int x = 100;

    while(1)
    {
        ptr = (char *) malloc(x++ * sizeof(char) / 2);
        printf("%p\n",ptr);
    }

    return 0;
}

1) 为什么当使用更大的数据类型(int、unsigned long long int、long double)时,进程会使用更少的内存,而使用更小的数据类型(int、char)会使用更多的内存?

2) 运行程序时,它会在达到一定数量后停止分配内存(在 Windows 7 64 位上约为 592mb,8GB RAM 交换文件设置为系统管理)。打印的输出如果显示为 0,则表示 NULL。为什么在达到这个阈值后停止分配内存而不耗尽系统内存和交换?

我在下面的帖子中发现有人尝试与我相同的事情,但他们没有看到内存使用有任何差异,但我是。 Memory Leak Using malloc fails

我已经在 Linux 内核 2.6.32-5-686 上尝试了代码,结果相似。

任何帮助和解释将不胜感激。

谢谢,

【问题讨论】:

  • 使用long long 应该会占用更多内存。你试过什么?您要输出的只是内存中存储它的位置,而不是分配的内存。在您的示例中,您分配了 50 个字节。
  • 只是想在别人之前说这句话,不要强制转换malloc的返回值。呜呜呜!!
  • 本地堆和系统堆是有区别的。在 Windows 中,应用程序不会获得非常大的本地堆,因此 malloc 会更快地耗尽内存。使用 VirtualAlloc() 从系统堆中分配。那么问题可能会变成小分配而不是实际内存的句柄/页面不足。
  • ricola: 为什么不呢?!建议怎么做?
  • 改用calloc。或者写入最后分配的字节。

标签: c memory memory-leaks memory-management malloc


【解决方案1】:

您如何查看您的内存使用情况?

1) 使用 char 分配时,每次分配的内存比使用 long 分配的内存少(通常是四分之一,但取决于机器) 由于程序本身外部的大多数内存使用工具不显示分配的内存,而是实际使用内存,它只会显示 malloc() 本身使用的开销,而不是你 malloc 的未使用内存。

更多的分配,更多的开销。

如果你用每个分配的数据填充 malloc 块,你应该得到一个非常不同的结果,以便实际使用内存。

2) 我假设您是从同一个工具中读取的?尝试计算您实际分配的字节数,它应该显示正确的数量,而不仅仅是“malloc 开销”。

【讨论】:

  • 我在 Windows 中使用任务管理器来查看内存使用情况。你的解释很有道理。当我用数据填充 malloc 块时,程序几乎立即崩溃。
【解决方案2】:

1) 这可能是由于内存是分页的,并且每个页面都具有相同的大小。如果您的数据无法放入一个页面并且位于两个页面之间,我认为它会移动到下一页的开头,从而在上一页的末尾造成空间损失。

2) 阈值更小,因为我认为每个程序都限制在一定数量的数据上,而不是您拥有的最大总内存。

【讨论】:

    【解决方案3】:

    1)通常内存是按页的倍数分配的,所以如果你要求的大小小于一个页,malloc 将至少分配一个页。

    2)这是有道理的,因为在多任务系统中,您不是唯一的用户,您的进程也不是唯一运行的进程,还有许多其他进程共享有限的资源,包括内存。如果操作系统允许一个进程无限制地分配它需要的所有内存,那么它就不是一个好的操作系统,对吧?

    最后,在 Linux 中,内核不会分配任何物理内存页面,直到您真正开始使用该内存之后,所以调用 malloc 实际上不会消耗任何物理内存,除了跟踪当然是分配本身。不过我不确定 Windows。

    编辑: 下面的例子分配了 1GB 的虚拟内存

    #include <stdio.h>
    int main(int agrc, char **argv)
    {
        void *p = malloc(1024*1024*1024);
        getc(stdin);
    }
    

    如果你跑到顶部,你会得到

    top -p `pgrep test`
    PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
    20   0 1027m  328  252 S    0  0.0   0:00.00 test
    

    如果你将 malloc 更改为 calloc,然后再次运行 top 你会得到 ​​p>

    top -p `pgrep test`
    PR   NI VIRT  RES  SHR S %CPU %MEM    TIME+ COMMAND              
    20   0  1027m 1.0g 328 S    0  1.3   0:00.08 test
    

    【讨论】:

    • 您对第 1 点和第 2 点的解释现在让我更清楚了。但是,当我在 Linux 下运行代码,然后运行 ​​free 命令时,可用内存量减少了。
    • @user1216551 我不确定,但我认为这可能是与跟踪分配本身有关的一些开销,我用一个例子更新了我的答案。
    • 我的代码在运行 top 时生成以下内容: PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 20 0 3071m 427m 328 R 44.3 85.0 0:11.84 malloc
    • @user1216551 这对我来说看起来很合理,如果 malloc 必须实际跟踪所有这些分配及其大小,我已经在这里运行了你的代码,我达到了 vert/res: 10.3g/804m
    【解决方案4】:

    1) 分配内存时,每次分配都会占用所请求内存的空间加上堆帧的大小。查看相关问题here

    2) 在 Windows 中,任何单个 malloc 的大小都被限制为 _HEAP_MAXREQ。有关更多信息和一些解决方法,请参阅 this question

    【讨论】:

      猜你喜欢
      • 2012-10-10
      • 1970-01-01
      • 1970-01-01
      • 2021-01-18
      • 2020-12-14
      • 2011-06-04
      • 1970-01-01
      • 2021-06-15
      • 1970-01-01
      相关资源
      最近更新 更多