exec()改变程序镜像之后,malloc分配的内存会发生什么?

43

我知道在Linux中调用exec()系统调用时,它将使用新的程序替换当前正在运行的进程。因此,当我复制一个新进程并运行exec()时,子进程将被新进程替换。

那么我从堆上分配的内存会发生什么?比如说,我想解析任意数量的命令并将其发送到exec()中。为了容纳这种任意数量的命令,我可能需要在某个时刻分配内存,因为我不认为我可以使用静态大小数组正确地完成这个任务,所以我很可能会使用malloc()或类似的函数。

我需要保持这些内存的分配直到执行完exec()之后,但是exec()永远不会返回。

操作系统会回收这些内存吗?


顺便提一下,这里有一个非常相似的问题:https://dev59.com/NFDTa4cB1Zd3GeqPHC4s - sharptooth
2个回答

39
当您调用fork()时,将创建调用进程的副本。这个子进程几乎与父进程完全相同,即通过malloc()分配的内存被保留,并且您可以自由地读取或修改它。但是,这些修改对于父进程来说是不可见的,因为父进程和子进程是完全独立的。
当您在子进程中调用exec()时,该子进程将被一个新进程所替代。根据execve(2)的解释:
execve() does not return on success, and the text, data, bss, and stack
of the calling process are overwritten by that of the program loaded.

通过覆写data段,exec()调用有效地回收了之前由malloc()分配的内存。

父进程不受影响。假设在调用fork()之前,在父进程中分配了内存,则该内存仍然在父进程中可用。

编辑:现代的malloc()实现使用匿名内存映射,请参见mmap(2)。根据execve(2),内存映射在exec()调用后不会被保留,因此该内存也被回收。


2
这并没有解释堆发生了什么。好吧,数据段被覆盖了,但这意味着堆被破坏了,而不是被重置。 - sharptooth
2
堆是数据段。在简单的实现中,malloc()会使用brk()来扩展数据段并获取更多内存。当数据段被覆盖时,它的大小也会被重置,内存也被有效释放。 - Petri Lehtinen
1
我认为,“堆破坏”通常意味着malloc()使用的堆中的数据结构被破坏了(例如,当指针被两次释放时)。当数据段被覆盖时,就没有什么可以被破坏的了。 - Petri Lehtinen
1
堆如何知道没有内存可用来服务用户请求并必须调用 brk()?它使用服务数据来实现。该服务数据驻留在数据段中。对该数据进行任何操作都将导致经典的堆破坏。 - sharptooth
1
实际上,在现代实现中,malloc() 使用通过 mmap() 获取的匿名内存映射。根据 execve(2) 的说明,内存映射在 exec() 后不会被保留,因此也不可能出现内存泄漏。 - Petri Lehtinen
显示剩余3条评论

5
整个堆——分配的内存,以及malloc用于管理它的所有逻辑——都是进程映像的一部分,该映像将被替换。 对于您的进程而言,它只是消失了。 当然,系统会恢复它并进行回收利用。

栈上的内存发生了什么事? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接