fork() 并释放所有分配的内存

Posted

技术标签:

【中文标题】fork() 并释放所有分配的内存【英文标题】:fork() and free all allocated memory 【发布时间】:2016-03-02 21:55:05 【问题描述】:

我正在编写一项服务(即后台进程),并希望通过共享库启动它。也就是说,想要使用该服务的人会链接到共享库,调用它的 start() 方法,该方法将分叉并返回。然后,fork 将运行该服务。

这种方法的问题是服务进程现在可能有很多它实际上不需要的遗留分配内存。有没有办法摆脱它并让分叉的进程分配自己的东西?我当然知道 exec(),但问题是

我需要一个可执行文件,但由于操作系统文件夹布局不同,它可能不在我预期的位置 我必须将所有潜在参数转换为字符串,以将其作为程序参数传递给 exec()

所以基本上,我正在寻找一种方法来调用任意函数 func() 带有一些应该在新进程中运行的参数,并且不应该传递给该函数的所有内容在新的过程中。有没有办法实现这个或类似的东西?

【问题讨论】:

这通常是不必要的,因为 Linux 使用写时复制 fork 实现,以便父子共享“复制”内存,直到子修改它。 你想要的并不真正可行。例如,假设库使用 stdio,并且 stdio 有一些分配的内存,你不希望你的“释放所有分配的内存”来释放它。所以你真正想要的是“释放所有不再需要的东西”,但是一个通用的函数怎么能知道什么是不需要的呢? @RossRidge 但是您想删除对副本的引用,因此当父级退出时它会全部消失。 @RossRidge 当父母或孩子修改它时它变得不共享。在极端情况下,父级继续修改所有内容而子级只做自己的事情,您最终会得到父级在调用 fork 之前分配的每一页内存的副本。 @DavidSchwartz 这样做的问题是您将执行库的客户端程序,而不是库的服务器可执行文件。 【参考方案1】:

这是一个有趣的问题,遗憾的是我没有很好的答案。我怀疑像 sbrk+close+munmap 这样的清理策略是否会可靠地允许任何基于 libc 的代码继续运行,所以我会尝试让 exec'ing 更好:

对于任何基于 exec 的解决方案,您应该能够将数据深度复制到 shm 以传递非字符串。这应该解决您的第二个问题。

以下是针对您的第一个问题的一些疯狂建议:

    不要:只要求可执行文件位于 PATH 或编译时目录中。

    这是透明的并且遵循 UNIX 理念。错误消息Can't find myhelper in PATH 不会减慢任何人的速度。大多数依赖于辅助可执行文件的工具都可以做到这一点,这很好。

    Make your library executable,并将其用作您的执行目标。您可以尝试通过某种自省来找到它的名称,也许是/proc/self/maps 或任何 glibc 提供的名称。

    与上面类似,但 exec python 或您可以合理确定存在的东西,并使用外部指针接口在您的库上运行函数。

    作为构建过程的一部分,编译一个小型可执行文件并将其作为二进制数据包含在您的库中。将其写入/tmp 并执行。

其中,我更喜欢 #1 的简单和透明,即使这是最无聊的解决方案。

【讨论】:

谢谢。我不想依赖 PATH,因为它是一个安全关键应用程序,谁知道攻击者可以在路径中的哪个位置放置替代可执行文件(例如 ~/bin)。其他一点可能会起作用。关于 exec 调用,我会将敏感数据传递给可执行文件(例如密码)。如果我将它们传递给 exec,它们会在对 ps 的调用中可见吗? 您可以随时清理您的路径,对/sbin/usr/sbin 具有写入权限的人已经拥有系统密码。您通过shm_open 按键传递的任何数据都将具有您在该调用中指定的权限。其他用户不能使用ps或其他任何方式阅读它,即使他们有密钥。

以上是关于fork() 并释放所有分配的内存的主要内容,如果未能解决你的问题,请参考以下文章

为啥反复分配和释放内存会耗尽系统所有内存?

为啥 free() 不释放所有分配的内存位置? [复制]

删除/释放由 malloc 分配并由 new [重复] 重用的内存

如何验证两个检查点之间是否已释放所有内存分配?

在 C 中退出程序时释放所需的分配内存

无法分配内存:fork:无法 fork 新进程?