【问题标题】:How come this C program does not crash?这个C程序怎么不崩溃?
【发布时间】:2015-04-13 16:32:16
【问题描述】:

这来自本书:Understanding and Using C Pointers

如果内存被重复分配然后丢失,那么程序 当需要更多内存但 malloc 无法分配它时可能会终止 因为它内存不足。在极端情况下,操作系统 可能会崩溃。下面的简单示例对此进行了说明:

char *chunk; 
while (1) { 
    chunk = (char*) malloc(1000000); 
    printf("Allocating\n"); 
} 

变量块分配的内存来自 堆。然而,这个内存在另一个块之前没有被释放 内存分配给它。最终,应用程序将用完 内存并异常终止。

所以我的问题: 我有这个示例代码:

int main(int argc, char *argv[]){
    char *chunk; 
    while (1) {
        chunk = (char*) malloc(100000000);
        printf("Allocating\n"); 
    }
}

我预计我的系统内存不足,但程序继续运行,我看到了文本

Allocating...

一直?

【问题讨论】:

  • 而且,你不会对这个内存做任何事情。那么它为什么会崩溃呢?即使它不能分配任何东西,malloc() 也会返回NULL,然后表演继续。
  • malloc() 本身不应该崩溃。如果无法分配内存,它将返回 NULL
  • @KorayTugay 人们可能会反对,因为你没有解释为什么你认为它应该崩溃。始终解释您的想法以及原因。
  • @KorayTugay,不,您不是“不断分配新的 100 Mbs”。您“不断尝试分配 100 Mbs”。那不是一回事。
  • malloc() 的手册,尤其是 RETURN VALUEERRORS(如果有)部分。

标签: c memory malloc


【解决方案1】:

当内存不足时malloc 可能返回NULL。添加一个检查。

while (1) {
    printf("Allocating\n"); 
    chunk = malloc(100000000);
    if ( chunk == NULL )
    {
       printf("Memory allocation not successful.\n");
    }
    else
    {
       printf("Memory allocation successful.\n");
    }
}

【讨论】:

  • 没错,如果你从不触摸它返回的页面,Linux 会返回有效值。当访问不再适合(虚拟)内存的页面时,它会崩溃。不知道为什么这会被赞成,这不是在 Linux 中发生的。
  • 我在cygwin上试过代码。过了一会儿,我收到了“不成功”的消息。
  • @RSahu,再次获得更多阅读理解。 Windows 在返回之前实际上保留了内存。
  • 平心而论,OP 没有提到他在哪个平台上运行。
  • 请不要在 malloc 的返回值中使用类型转换。
【解决方案2】:

我猜是在 Linux 上?

仅仅因为你得到一个指针并不意味着你实际上保留了那个内存。您必须亲自触摸页面才能使其成为您的。

【讨论】:

  • 所以你是说它会在第一次读/写时崩溃?不太可能。如果不是 null 当然..
  • 我在循环中添加了这一行,仍然没有崩溃:*chunk = 'c';
  • 您只接触了一个页面。您需要触摸该序列中的每一页,然后等待它填满您的 RAM 您的页面文件/交换。 @Eugene,第一次读/写?不,我从来没有说过。
  • @Blindy 那么“触摸”是什么意思?
  • @nos 不是vm.overcommit_memory=2吗?根据this
【解决方案3】:

您运行的程序没有错误。它不必异常终止。提前终止的原因是它消耗了你电脑的所有内存,所以如果你没有采取正确的措施,它就会死掉。

Linux(以及一般的 unix)对系统上运行的进程施加了一些限制。在 linux 中,所有这些限制(参见 ulimit(2) 系统调用)默认情况下都固定为unlimited

当 linux 中的一个进程试图获得比系统拥有的更多的内存并分配剩余的虚拟内存时,内核会选择一个进程(最好的候选者是试图吃掉所有内存的进程)并杀死它以恢复一些内存。这也许就是您阅读的文本说异常终止的原因。您注意到这一点是因为系统试图交换您正在分配的所有内存并且交换器需要所有内核关注(因此您的系统似乎会挂起一段时间 --- 它没有,只是等待)

但是你可以做这样的测试:尝试限制分配给进程的虚拟内存(使用 ulimit 命令,参见 bash(1)),以便系统可以应对内存消耗程序.使用命令

$ ulimit -v 100000 # this allows for 100.000 kb of virtual memory

然后重新运行程序(它将能够扩展到 100Mb 并且不再有)。你会看到它不会停止。它永远运行。一旦它用尽了所有的内存,ma​​lloc(3) 开始返回NULL 并且进程永远不会停止。您将看到(通过 ps(1) 命令)该程序已分配到您施加的限制并且没有更多,并且它正在运行,消耗 100% 的 cpu 时间。而一切都在掌控之中。我尝试了您的程序的以下变体:

#include <stdlib.h>
#include <stdio.h>
char *chunk;
main()
{
    int i = 0;
    while (malloc(1000000)) i++; 
    printf("run for %i times.\n", i);
}

它会在内存不足之前计算成功分配的数量,并将该数字打印在stdout 上。将 ulimit 固定为 100Mb (ulimit -v 1000000) 后,此程序输出:

$ pru
run for 97 times.

(您会看到它低于 100Mb)所以,瞧!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2017-04-01
    • 1970-01-01
    相关资源
    最近更新 更多