如何将内存从进程返回到操作系统

Posted

技术标签:

【中文标题】如何将内存从进程返回到操作系统【英文标题】:How to return memory from process to the OS 【发布时间】:2012-08-16 13:22:51 【问题描述】:

我在各种操作系统中遇到内存管理问题。

我的程序是一个服务器,它执行一些可能需要几 GB 内存的处理。之后,它会释放大部分内存,同时等待几个小时,直到另一个请求到达。

在 AIX 和 Solaris 上,我观察到以下行为,

当我释放内存时,内存不会返回给操作系统。进程使用的虚拟内存量总是增加 - 永远不会减少。物理内存也是如此,直到它的极限。因此,我们似乎也在睡眠模式下使用了所有这些内存。

这块内存什么时候可以返回给操作系统?我怎样才能做到?

Linux 不同:它似乎有时会返回内存,但我无法理解何时以及如何。例如,我有一个场景,请求之前的进程是 100MB,然后是峰值 700MB,而在释放所有请求之后它下降到 600MB。我不明白——如果 Linux 将内存归还给操作系统,为什么不全部归还呢?

【问题讨论】:

我看到 Java 12 现在承诺在某些情况下能够将内存返回给操作系统 - openjdk.java.net/jeps/346 【参考方案1】:

我假设内存的分配方式(可能还给操作系统)在 libc 中。您正在使用的编程语言/库堆栈可能是这个原因。

我假设 glibc 将在堆顶部返回非碎片化内存。您的进程可能会分配 10MB 的数据,它将一直使用。之后,将分配 500MB 用于处理的数据。 之后,即使在处理(可能是处理的结果)之后仍保留的一小部分数据被分配。之后再分配 500MB 内存布局为:

|使用 10MB|500MB 处理|1MB 结果|500MB 处理| = 总计 1011 MB

释放1000MB后,内存布局为

|使用 10MB|释放 500MB|结果 1MB|释放 500MB| glibc 现在可能会在最后返回内存...... |10MB 使用|500MB 释放|1MB 结果| = 511 MB“正在使用” 也只使用了其中的 11MB。

我认为会发生这种情况,您需要做进一步的研究(想到单独的内存池)以确保所有内存都将被释放

【讨论】:

【参考方案2】:

你应该看看分页是如何工作的。如果小于 getpagesize() 则无法返回内存。

【讨论】:

【参考方案3】:

大多数情况下,在进程终止之前,内存不会返回给系统。根据操作系统和运行时库,内存可能会返回给系统,但我不知道有什么可靠的方法来确保这会发生。

如果处理需要几 GB 内存,请让您的服务器等待请求,然后生成一个新进程来处理数据 - 您可以使用管道与服务器通信。处理完成后,返回结果并终止生成的进程。

【讨论】:

【参考方案4】:

glibc 库(通常用作 Linux 中的标准 C 库)可以通过两种方式分配内存 - 使用 sbrk() 或使用 mmap()。它将使用 mmap() 进行足够大的分配。

用 sbrk() 分配的内存不能轻易地再次放弃(仅在特殊情况下,据我所知 glibc 甚至没有尝试)。使用 mmap() 分配的内存可以使用 munmap() 返回。

如果您依赖能够将内存返回给操作系统,您可以直接使用 mmap() 而不是 malloc();但是如果你分配很多小块,这将变得低效。您可能需要在 mmap() 之上实现自己的池分配器。

【讨论】:

+1 用于 mmap。我没有想到。但如果需要很多小块,我会使用专门的流程。 free 有时可能会通过munmap 向内核释放内存。我认为它可以为足够大的内存区域做到这一点。 所以问题是 - 我如何说服 glibc() 调用 munmap?是否有一些编译器选项、系统调用等会改变行为? 也许this 会有所帮助。【参考方案5】:

我认为唯一可靠可移植的方法是生成一个新进程来处理您的请求。进程退出后,操作系统将获取所有相关的内存。

不幸的是,您在生成此进程和进程间通信方面效率低下(我注意到您正在进行大量处理 - 我不知道这是否意味着您的进程间通信具有相当大的数据需求) .但是,您将获得所需的内存行为。请注意,操作系统不应复制实际 JVM 消耗的内存,前提是您生成 相同 JVM 二进制映像。

【讨论】:

谢谢,但是 spawn 对我不起作用。我正在运行 C++。 (我应该之前说过)

以上是关于如何将内存从进程返回到操作系统的主要内容,如果未能解决你的问题,请参考以下文章

我是如何学习写一个操作系统:内存管理和段页机制

从 kswapd0 进程CPU占用过高 到计算机内存详解

fork函数详解(附代码)

将动态分配的内存从 C++ 返回到 C

Linux - 用户态内存映射 和 内核态内存映射

作为开发人员,我应该如何考虑操作系统虚拟内存机制