【问题标题】:UNIX vs Windows memory deallocationUNIX 与 Windows 内存释放
【发布时间】:2010-09-19 03:46:53
【问题描述】:

我的理解是,在 unix 中,当内存被释放时,内存不会返回给操作系统,它会留在进程中以再次用于下一次调用 malloc。

在 windows 上,我知道内存实际上是返回给操作系统的。

这两种做事方式有什么大的区别,还是只是做同一件事的两种不同方式?如果这两种方法有什么优缺点,分别是什么?

编辑:感谢您的澄清。我一直认为这是操作系统的问题(因为在类 UNIX 系统中进程的大小似乎从未减小,但在 Windows 中却如此)。

【问题讨论】:

  • 进程在 Windows 上减小的大小可能是另一回事:当窗口最小化时,Windows 会修剪驻留集的大小,而您可能正在任务管理器中查看该值。例如,Firefox 不得不禁用 Windows 的“功能”,这太慢了。

标签: windows language-agnostic unix memory-management


【解决方案1】:

来自Memory Management这篇文章

Malloc 通常不会将释放的内存返回给操作系统;它一直归进程所有,直到它终止。该进程可以在下次请求更多内存时重用它,但其他程序将无法访问它,即使没有其他内存可用。作为推论,程序的内存占用量是在任何时候进行的最大分配的大小。因此,明智的做法是尽快释放不需要的对象,尤其是大型对象,以尽量减少占用空间。

那篇文章确实建议在 Windows 中,至少对于 C 程序,内存不会返回给操作系统。

所以我不确定您对 Windows 内存释放的概括。

也就是说,您可以尝试Emulating UNIX Memory Management Under Microsoft Windows,通过在 Windows 上实现低级系统调用 sbrk 和 mmap/munmap。

【讨论】:

    【解决方案2】:

    我不了解 Windows,但在 UNIX 上,brk() 调用用于将更多内存带入地址空间以供malloc() 调用使用。

    在进程终止之前,我从未见过此内存返回给操作系统。您通常可以使用top 等工具看到这一点。

    我怀疑 Windows 的行为会相同,但我知道 Windows 具有除 malloc() 之外的其他分配函数,它可能会执行此操作(Win32 API 的一部分)。

    【讨论】:

      【解决方案3】:

      请注意,在接下来的内容中,我对 Windows 的了解远多于 Unix ...

      在任何情况下,内存分配和释放实际发生的情况并不完全是您所描述的。这是因为这里有两个非常不同的概念在起作用:计算机拥有的物理内存,以及程序的虚拟地址空间,即您的程序认为可以使用的内存。

      当您的程序向操作系统请求更多内存时,实际发生的情况是程序中以前不可用的虚拟地址空间被设置为程序可以访问。现代操作系统不能仅仅通过拥有一个“真实”(即物理)内存池来工作,当它们发出分配请求时它会分发给进程:它为每个正在运行的程序维护虚拟地址空间,并且,当程序实际访问该虚拟地址空间的一部分,确保将其映射到某些物理内存,可能通过将另一个程序的地址空间的某些部分换出到磁盘上的交换文件。

      作为一个例子,在 Windows 上,每个线程都以(默认情况下)分配给它的 1 MB 堆栈空间开始。这并不意味着每个线程都会消耗一兆字节的机器物理内存:只是设置了地址空间以便它可以使用。从这个意义上说,考虑操作系统给你的程序内存,然后程序把它还给它是行不通的——它只是不能那样工作。

      【讨论】:

        【解决方案4】:

        这完全取决于您使用的 C 运行时库。没有特定的 UNIX 方式或 WINDOWS 方式。每个编译器供应商(HP、SUN、MS、GNU)都附带了他们自己的包含 malloc 逻辑的运行时库。 malloc 的每个实现将根据操作系统运行相同/不同。 UNIX/LINUX/Windows 都不需要免费的“实际返回”内存给操作系统。那太贵了(因为你的 alloc() 会是非常小的块)

        最近 mozilla Firefox 从 *BSD OS 借用了 malloc() 实现。他们选择使用与他们的编译器供应商(在本例中为多个——gcc 和 VC++)提供的不同的 malloc。因为他们想要某种行为,所以他们得到了他们想要的。

        【讨论】:

          【解决方案5】:

          唯一不能轻易将分配的内存归还给系统的操作系统是 OS X - 引用 Firefox 3 Memory Usage

          经过广泛的测试和 Apple 员工的确认,我们 意识到没有办法 分配器给未使用的页面 在保留地址的同时恢复内存 保留范围..(您可以取消映射它们 并重新映射它们,但这会导致一些 竞争条件,而不是 高性能。)有些API声称 去做(madvise() 和 msync()) 但他们实际上并没有做任何事情。

          【讨论】:

            【解决方案6】:

            正如其他提到的,这与 malloc 实现的联系比操作系统本身更多。在 linux 上,使用 glibc,内存实际上总是返回给操作系统,超过一定大小:glibc malloc 使用 mmap 进行大分配(由 MMAP_THRESHOLD 控制),在这种情况下,free 调用 munmap,它会自动释放保留的内存。低于该阈值,它会使用 brk,并且 free 在这种情况下不会“归还”内存。

            注意,上面的解释并不准确:准确地说,你需要知道物理内存、虚拟内存等的区别……这里解释得很好:

            http://blogs.msdn.com/oldnewthing/archive/2004/08/22/218527.aspx

            【讨论】:

              【解决方案7】:

              其他发帖者已经对平台特定角度发表了评论。但是由于您专门询问 malloc,让我们看看 C 标准是怎么说的:

              "free函数使ptr所指向的空间被释放,也就是使 可供进一步分配。”

              这似乎是一个非常明确的要求,即不将内存返回给操作系统。您偶尔会看到依赖这种行为的程序:

              int main(void)
              {
              
                  void *p = malloc(AS_MUCH_MEMORY_AS_I_WILL_EVER_NEED);
              
                  if (p != 0)
                  {
                      free(p);
                      /* malloc should always work for rest of program */
                  }
              }
              

              但是,当这个问题出现在 comp.lang.c 上时,一些发帖者指出了这部分:

              “malloc 函数返回一个空指针或一个指向分配空间的指针。”

              这表明任何对 malloc 的调用都可能失败。该标准的意图似乎是不将内存归还给操作系统,但在语言律师看来,这个问题并不是 100% 确定的。

              【讨论】:

                【解决方案8】:

                在这方面,Windows 和 Unix 没有太大区别。

                两者都有两个级别的分配。操作系统以大块(一页或更多;在 x86 上,页大小通常为 4096 字节)为进程分配内存。在进程中运行的运行时库会细分该空间并将其中的一部分分配给您的代码。

                要将内存返回给操作系统,首先必须将从这些大块之一分配的所有内存释放到运行时库。如果需要,运行时库可以告诉操作系统释放那块内存。

                在 Linux 上,您有 brkmmapbrk 控制分配给您的进程的大块内存的大小;你可以扩大或缩小它,但只能在一端。 malloc 传统上在需要更多内存来分配时扩展这块内存,并在可能的情况下缩小它。但是,缩小并不容易;最后需要一个单字节的不合时宜的分配才能使其无法收缩,即使该分配之前的所有内容都已被释放。这就是“Unix 不会释放内存”这个梗的来源。

                不过,也有匿名的mmap。匿名mmap 向操作系统请求一块内存,可以放在进程内存空间的任何位置。当不再需要这个块时,可以很容易地返回它,即使有后来的分配还没有释放。 malloc 也使用 mmap (特别是对于大型分配,整个内存块在被释放后可以很容易地返回)。

                当然,在 Windows 和 Linux 上,如果您不喜欢运行时库中的内存分配器(或多个分配器)的行为,您可以使用自己的,向操作系统询问内存并按照您想要的方式细分它(或者有时向另一个分配器询问内存,但在更大的块中)。一个有趣的用途是为与任务相关的所有内存分配器(例如,Web 服务器请求),在任务结束时将其完全丢弃(无需单独释放所有部分);另一个有趣的用途是固定大小对象(例如,五字节对象)的分配器,它可以避免内存碎片。

                【讨论】:

                  【解决方案9】:

                  malloc 函数返回一个空指针或一个指向分配空间的指针。"

                  这表明任何对 malloc 的调用都可能失败。似乎标准的意图是不将内存返回给操作系统。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-09-12
                    • 1970-01-01
                    • 2014-08-16
                    • 2012-01-16
                    • 2014-05-18
                    • 2010-09-26
                    相关资源
                    最近更新 更多