【问题标题】:heap overflow affecting other programs影响其他程序的堆溢出
【发布时间】:2017-06-07 04:31:37
【问题描述】:

我试图为 malloc 创建返回 NULL 指针的条件。在下面的程序中,虽然我可以看到 malloc 返回 NULL,但一旦程序被强制终止,我看到所有其他程序都变慢了,最后我不得不重新启动系统。所以我的问题是堆内存是否与其他程序共享?如果没有,其他程序应该不会受到影响。操作系统在执行时是否没有分配一定数量的内存?我正在使用 Windows 10,Mingw。

#include <stdio.h>
#include <malloc.h>

void mallocInFunction(void)
{
    int *ptr=malloc(500);
    if(ptr==NULL)
    {
        printf("Memory Could not be allocated\n");
    }
    else
    {
        printf("Allocated memory successfully\n");
    }
}


int main (void)
{
    while(1)
    {
        mallocInFunction();
    }

    return(0);
}

【问题讨论】:

  • void *mallocInFunction(void) { void *ptr = malloc (500); ... return ptr; } 允许您衡量分配的成功或失败。然后while (mallocInFunction()) {} 在main。你的内存是共享的(不完全像虚拟内存分配给每个可执行文件),当你开始用完时,你的系统应该关闭非必要的进程。
  • 程序在需要时请求增加堆大小并且操作系统提供更多内存......然后其他程序变慢,因为操作系统最终使用磁盘交换空间来提供其他程序,因为您的程序使用了所有真实的记忆。 (很粗略)
  • 其他程序可能会在一段时间内变慢,但很快应该在它们的页面被换入时恢复正常操作。如果您的交换量较少,操作系统也可能不得不终止一些进程它稍后将不得不重新开始。如果您的机器在这样的实验之后完全无法使用,您可能想在实验之前尝试增加交换空间(在 Windows 中称为虚拟内存)。通常的交换大小等于物理内存大小。
  • @M.M.在这种情况下,问题可能是交换也被填满了,因为 malloc 仅在交换也已满后才会返回 NULL。
  • @AjayBrahmakshatriya 我认为 Windows 通常不会返回 NULL,它只是延迟分配,然后在交换填满时终止进程

标签: c malloc heap-memory


【解决方案1】:

所以我的问题是堆内存是否与其他程序共享?

物理内存 (RAM) 是所有进程共享的资源。操作系统决定为每个进程分配多少 RAM,并随着时间的推移进行调整。

如果没有,其他程序应该不会受到影响。操作系统在执行时是否没有分配一定数量的内存?

在程序开始执行时,操作系统并不知道程序需要或需要多少内存。相反,它处理发生的分配。除非另有配置,否则它通常会尽其所能让程序的分配成功,因为大概有一个原因,程序正在做它正在做的事情,而操作系统不会尝试第二次猜测它。

【讨论】:

    【解决方案2】:

    ...堆的内存是否与其他程序共享?

    嗯,C 标准并不完全需要堆,但在任务切换、多用户和多线程操作系统的上下文中,当然 > 内存在进程之间共享! C 标准不需要任何,但这都是很常见的东西:

    • CPU 缓存往往更适合经常执行的代码,尽管这可能会被交换很多次;可能会或可能不会交换到堆。
    • 任务切换导致寄存器被交换到其他形式的内存;可能会或可能不会交换到堆。
    • 整个页面在磁盘之间交换,因此当您的操作系统将执行从您的程序切换到其他程序时,以及当您的程序再次执行时,其他程序可以使用它们原因。这可能涉及也可能不涉及操作堆。

    FWIW,您指的是具有allocated storage duration 的内存。最好避免使用像 heap 和 stack 这样的术语,因为它们实际上没有意义。您所指的内存位于硅芯片上,无论它使用堆还是堆栈。

    ...操作系统在执行时是否没有分配一定数量的内存?

    说到硅芯片和执行,您的操作系统可能只控制 一个 处理器(我确信其中包含一些逻辑电路和内存的硅芯片)来执行许多程序!总结这篇文章,是的,您的程序很可能与其他程序共享这些硅芯片!

    顺便说一句,我认为 heap overflow 并不像您认为的那样。

    【讨论】:

      【解决方案3】:

      您的问题无法在语言 C 的上下文中回答。对于C,没有堆、进程、...

      这样的东西

      但它可以在操作系统的上下文中回答。甚至有点笼统,因为许多现代多任务操作系统都做类似的事情。

      鉴于现代多任务操作系统,它将为每个进程使用虚拟地址空间。操作系统管理固定大小的物理 RAM 并将其划分为页面,当进程需要内存时,这些页面映射到进程的虚拟地址空间(通常使用与物理地址不同的虚拟地址)。因此,当操作系统本身和正在运行的进程要求所有内存页面时,操作系统通常会将其中一些未在活动使用的页面保存到磁盘中的 交换区域,以便将此页面作为新页面提供给下一个请求的进程。但是当原始页面被触动时(这通常是free() 的情况,见下文),它必须首先再次从磁盘加载,但要有一个空闲页面,另一个页面必须保存到交换空间。

      就像所有磁盘 I/O 一样,这很慢,这可能就是您在此处看到的情况。

      现在要完全理解这一点:malloc() 是做什么的?它通常从操作系统请求增加自己进程的内存(如果有必要,操作系统通过映射另一个页面来做到这一点),并通过在其中写入一些关于请求的内存块的信息来使用这个新内存(所以free() 以后可以正常工作)并最终返回一个指针,指向一个可供程序免费使用的块。 free() 使用malloc() 写入的信息,对其进行修改以指示此块再次空闲,并且它通常无法将任何内存归还给操作系统,因为还有其他malloc()d块在同一页面中。它会在可能的情况下归还内存,但这是在大量使用动态分配的典型场景中的例外。

      因此,您的问题的答案是:是的,RAM 是共享的,因为只有一组物理 RAM。操作系统会尽其所能隐藏这一事实并虚拟化 RAM,但如果一个进程消耗了所有内存,这将产生明显的影响。

      【讨论】:

        【解决方案4】:

        malloc() 不是系统调用,而是 libc 库函数。因此,当程序通过 malloc() 请求分配内存时,系统调用 brk()/sbrk() 或 mmap() 到分配的页面,更多细节here。

        请记住,您获得的内存本质上都是虚拟的,这意味着如果您有 3GB 的物理 RAM,您实际上可以分配几乎无限的内存。那么这是怎么发生的呢?这通过称为“分页”的概念发生,系统将数据从辅助内存存储(HDD/SDD)存储和检索到主内存(RAM),更多细节here。

        因此,根据这个理论,内存不足通常很少见,但是像上面这样检查系统限制的程序,可能会发生这种情况。这很好地解释了here。

        现在,为什么其他程序有点挂起或缓慢?因为它们都共享相同的操作系统,并且系统正在缺乏资源。事实上,系统有时会崩溃并再次重新启动。

        希望这有帮助吗?

        【讨论】:

        • Windows 问题的 linux OOM 链接?你不妨使用this analogy ;)
        • 我的努力是解释幕后发生的事情,这不是写在石头上,而是事件链(是的,特定于 Linux 系统)。示例 malloc() 以各种方式管理内存(最佳适配、首次适配、最后适配、伙伴等),这是特定于实现的,但它们都遵循的协议是相同的。如果我错了,请纠正我:)
        猜你喜欢
        • 1970-01-01
        • 2018-08-05
        • 1970-01-01
        • 2021-07-23
        • 2019-01-20
        • 2010-12-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多