【问题标题】:malloc return value as while conditionmalloc 返回值作为 while 条件
【发布时间】:2017-04-16 07:15:40
【问题描述】:

在我遇到的一堆关于动态内存分配的程序中,当需要分配动态内存时,我总是找到相同的代码:

int *pointer = (int *)malloc(sizeof(int));

if(pointer == NULL)
    exit(1); // or return 1

// else the program keep running

我想知道为什么不使用它,或者至少我从未见过它,类似的东西:

int *pointer
while((pointer = (int *)malloc(sizeof(int)) == NULL);

我想到了它,我想出的唯一一件事是,如果你不能分配新内存是因为堆上没有更多的东西了,所以第二个例子会变成一个 无限循环。那正确吗?因为如果内存分配由于某些其他原因(我真的不知道是哪个原因)失败,那么将分配放在循环中可能会解决问题。

我错过了什么吗?哪种“风格”更受欢迎?

【问题讨论】:

  • 第二个例子在失败时确实会变成一个无限循环,而第一个例子会立即退出......你有什么理由更喜欢无限循环而不是立即退出?我不完全确定我理解你的问题......
  • 这是否有可能在多线程程序中运行?如果是这样,可以想象线程 1 可能无法分配,因为线程 2 已经抢占了所有空间。如果线程 2 随后释放了它已分配的一些空间,那么线程 1 可能能够获得一些如此释放的内存——然后可能需要重试 malloc,可能在尝试之间有某种暂停,而不是全速锤击分配器。否则(单线程程序),重试没有意义。

标签: c memory memory-management


【解决方案1】:

在循环中重试 malloc 实际上是有意义的(但不是在无限循环中),至少在 Windows 机器上是这样。在这里查看我的详细答案: https://stackoverflow.com/a/30495537/2986286

当页面文件设置为自动增长时,当页面文件大小必须增长时,内存分配可能会失败。重试分配有助于解决此问题。

【讨论】:

    【解决方案2】:

    我能想象的唯一一个重试失败的 malloc 的用例是在支持 bursts 来自不同程序的内存分配的环境中运行的程序,很快就会完全释放它。在这种情况下,无法获取所有必要内存的程序应该等到另一个程序释放足够多的内存才能继续。

    但这需要程序员非常谨慎,因为有一个直接的极端情况。假设系统有 4 GB 的 free 内存,即没有任何内存消耗进程正在运行。假设一个可以获得 1.5GB,还需要 1.5,而另一个也有 1.5GB,还需要 1.5。您处于一个很好且干净的死锁中,因为只有 1 GB 可用,并且两个进程都在等待另一个释放任何东西。

    即使无法获取所有必要内存的进程必须在进入循环之前释放所有内容,您也可能陷入竞争条件,即进程仅获取它们需要的部分内容,无法获取所有内容,如果没有,则释放并再次循环如果能够一次获得全部,则处理。

    由于我们更喜欢健壮的系统,因此程序假定内存可用,如果不可用则中止。现在是一个人类的问题,选择是增加内存,改变程序让它使用更少的内存,还是序列化处理同时只有一个大程序或......

    【讨论】:

      【解决方案3】:

      内存分配在失败时不会重试,因为没有理由期望一旦失败后,它们将在任何后续尝试中成功而没有任何更改。正如您所观察到的,这当然适用于内存不足的情况,但它也适用于您可以想象的任何其他合理的故障模式。毕竟,如果malloc() 可以自行恢复,那么它一开始就不需要失败。

      因此,像您建议的那样严格的内存分配循环与根本不测试分配是否成功一样糟糕。在失败的情况下,无论失败的原因是什么,都极有可能使程序陷入死循环。

      【讨论】:

        【解决方案4】:

        如果没有剩余内存,确实会导致你的程序陷入无限忙循环,占用CPU。

        如果您的计算机内存不足,我认为您最不需要做的就是在 RAM 中保留一些幽灵进程,从而窃取 CPU。

        您的程序最好优雅地终止并通知用户他们的内存不足。因为在大多数计算机上,内存不足是一种相当严重的错误情况。

        这又可能是由内存泄漏、堆损坏和其他使您的程序的执行环境不稳定的令人讨厌的事情引起的。这可能意味着您自己的流程中的错误应该受到指责。这反过来意味着该过程不会自行从错误状态中恢复。

        【讨论】:

          【解决方案5】:

          根据malloc 手册页,malloc 只能失败并出现一个错误,即ENOMEM,即内存不足错误。在这种情况下,重试没有意义。

          在while循环中重试的风格通常跟在其他系统调用之后,例如read(2)open(2)select(2)等可以返回-1表示错误并设置errnoEINTR,表示他们因为一个信号被打断了。在这种情况下,您通常希望再次重试呼叫。

          【讨论】:

            猜你喜欢
            • 2013-03-10
            • 1970-01-01
            • 2015-04-29
            • 2020-09-03
            • 2017-03-23
            • 1970-01-01
            • 2023-03-13
            • 2017-10-08
            • 2020-10-16
            相关资源
            最近更新 更多