child 进程在退出前未释放内存是否泄漏?
Is it a leak if memory isn't freed in a child process before exit?
到处都有类似的问题,其中一个已关闭来自 this 堆栈交换站点。但即便如此,我还是从阅读中学到了很多东西 none,其中完全回答了我的问题。
问题来了,说我有这个程序(是一个非常简化的版本)
inline void execute(char *cmd)
{
int exitstat = 0;
//lots of other thins happed
exitstat = execve(cmd, cmdarg, environ);
free(cmd), free(other passed adress); ## DO I NEED THIS, since I am already about to exit
_exit (exitstat);
}
int main(void)
{
int childstat;
char *str = malloc(6); //I also have many more allocated space in heap in the parent process
strcpy(str, "Hello");
pid_t childid = fork() //creat a child process, which will also get a copy of all the heap memories even tho it is CoW.
if (childid < 0)
exit(-1);
if (child == 0)
{
execute(str);
}
else
{
wait(&childstat);
free(str);
}
//do somethign else with str with other functions and the rest of the program
}
在这个程序中,parent
process
做了一段时间,在heap
分配了很多进程,free
一些,其他留着稍后在某个时候它想要执行一些命令,但它不想终止,所以它创建了一个 child
来执行它的咬合。
child 然后调用另一个函数,该函数将执行一些任务,最后使用 execve
到 execute
传递给它的命令。如果成功就没有问题,因为执行的程序将处理所有分配的 spaces,但如果失败,child 将退出并返回一个状态码。 parent 等待 child 回答,当它回答时,它会继续下一个例程。这里的问题是,当 child
执行失败时,所有堆数据仍然分配,但这有关系吗?因为,
- 即将在下一行退出,
- 尽管我刚开始使用它,但我了解到在
fork
期间创建了一个新的 process
,因此内存泄漏不应影响 parent
,因为child
快要死了
- 如果我的假设是正确的,而且这个泄漏实际上并不重要,为什么
valgrind
会为他们哀叹?
- 是否有更好的方法来
free
child 堆中的所有内存而不实际将所有内存(本例中的 str,
和其他内存)传递给执行函数,每次都费力地调用free
? kill()
有这方面的机制吗?
编辑
这是工作代码
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
inline void execute(char *cmd)
{
extern char **environ;
int exitstat = 0;
char *cmdarg[2];
cmdarg[0] = cmd;
cmdarg[1] = NULL;
exitstat = execve(cmd, cmdarg, environ);
free(cmd);
_exit (exitstat);
}
int main(void)
{
int childstat;
char *str = malloc(6);
pid_t childid;
strcpy(str, "Hello");
childid = fork();
if (childid < 0)
exit(-1);
if (childid == 0)
{
execute(str);
}
else
{
wait(&childstat);
free(str);
}
return (0);
}
当 child 进程内部有空闲时,这里是 valgrinds 结果。
当运行与child进程中的free
被注释时。(#free(cmd)
在execute函数中)。
如您所见,总体错误 () since this programm is short lived. But in my real program which has an infinite loop every problem in the child () 无关紧要。所以我问我是否担心这个 child 进程在退出之前泄漏的内存并追捕它们,或者只是让它们保持在另一个虚拟 space 中并在它们的进程退出时被清理(但在那种情况下,如果相应的进程在退出期间清理它们,为什么 valgrind 仍然抱怨它们)
exitstat = execve(cmd, cmdarg, environ);
free(cmd), free(other passed adress);
如果成功,execve
不会return。之后没有代码执行,执行终止并启动 cmd
进程。操作系统无论如何都会释放当前进程持有的所有内存。如果 execve
调用成功,代码 free(cmd), free(other passed adress);
将不会执行 。
唯一可能与这些留置权相关的情况是 execve
错误。如果 execve
return 出现错误,是的,您应该释放该内存。我非常怀疑大多数带有 execve
的程序实际上会这样做,我相信他们只会在 execve
调用失败后调用 abort()
。
inline void execute(char *cmd)
请阅读 inline
。 inline
很棘手。我建议不要使用它,忘记它的存在。我怀疑这里的目的是制作一个内联函数——编译器无论如何都没有其他函数可以选择。修复代码中的拼写错误后,由于对 execute
的未定义引用,我无法编译代码 - inline
必须删除。
The problem here is that when the child fails to execute all the heap data remains allocated, but does that matter?
最终取决于你在child失败后想做什么。如果你只想调用 exit
并且你不关心这种情况下的内存泄漏,那么就不要关心它也没关系。
我看到 glibc exec*.c 函数尽量避免动态分配并使用可变长度数组或 alloca()
。
If my assumption is correct and this leaks doesn't actually matter, why does valgrind lament about them?
没有。如果您更正代码中的所有错误,那么 valgrind
将不会在调用 execve
之前“哀叹”内存泄漏(好吧,除非 execve
调用失败)。
Would there be a better way to free all the memories in the child heap with out actually passing all the memores (str, and the others in this example) to the execute function and laboriously call free each time?
“更好”往往是基于意见的。主观上:没有。但是 writing/using 自己的动态分配包装器和垃圾收集器来释放所有内存也是一种选择。
does kill() have a mechanism for this?
不,发送信号似乎与释放内存无关。
没有简单的解决方案。
终止时,OS 将为进程释放所有内存。这意味着您 没有 来释放所有内容。然而,对于不再需要的内存,通常最好尽快释放它。这样就留下了诸如缓冲区之类的东西,可能会一直使用到终止前的最后一刻。
释放内存的原因。
- 我只能想到一个。如果你在最后使用了大量的块,那么很难从谷壳中挑选出小麦。要么你最终得到大量无人查看的日志,要么你必须维护一个抑制文件。无论哪种方式,您都有可能忽视真正的问题。
不释放内存的原因
- 性能提升较小
- 有时候要释放所有东西是相当困难的。例如,如果您使用
putenv()
那么要知道字符串是被添加(并且需要释放)还是被替换(一定不能被释放)就有点棘手了。
- 如果您需要使用
atexit()
来释放东西,那么您可以通过 atexit()
调用的函数数量是有限制的。如果您在许多模块中释放了很多东西,那可能是个问题。
我的建议是尝试释放大部分东西,但不要着急,否则你会被递减法则所困扰 returns。对于难以释放的百分之几,明智地使用抑制文件。
到处都有类似的问题,其中一个已关闭来自 this 堆栈交换站点。但即便如此,我还是从阅读中学到了很多东西 none,其中完全回答了我的问题。
问题来了,说我有这个程序(是一个非常简化的版本)
inline void execute(char *cmd)
{
int exitstat = 0;
//lots of other thins happed
exitstat = execve(cmd, cmdarg, environ);
free(cmd), free(other passed adress); ## DO I NEED THIS, since I am already about to exit
_exit (exitstat);
}
int main(void)
{
int childstat;
char *str = malloc(6); //I also have many more allocated space in heap in the parent process
strcpy(str, "Hello");
pid_t childid = fork() //creat a child process, which will also get a copy of all the heap memories even tho it is CoW.
if (childid < 0)
exit(-1);
if (child == 0)
{
execute(str);
}
else
{
wait(&childstat);
free(str);
}
//do somethign else with str with other functions and the rest of the program
}
在这个程序中,parent
process
做了一段时间,在heap
分配了很多进程,free
一些,其他留着稍后在某个时候它想要执行一些命令,但它不想终止,所以它创建了一个 child
来执行它的咬合。
child 然后调用另一个函数,该函数将执行一些任务,最后使用 execve
到 execute
传递给它的命令。如果成功就没有问题,因为执行的程序将处理所有分配的 spaces,但如果失败,child 将退出并返回一个状态码。 parent 等待 child 回答,当它回答时,它会继续下一个例程。这里的问题是,当 child
执行失败时,所有堆数据仍然分配,但这有关系吗?因为,
- 即将在下一行退出,
- 尽管我刚开始使用它,但我了解到在
fork
期间创建了一个新的process
,因此内存泄漏不应影响parent
,因为child
快要死了 - 如果我的假设是正确的,而且这个泄漏实际上并不重要,为什么
valgrind
会为他们哀叹? - 是否有更好的方法来
free
child 堆中的所有内存而不实际将所有内存(本例中的str,
和其他内存)传递给执行函数,每次都费力地调用free
?kill()
有这方面的机制吗?
编辑
这是工作代码
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
inline void execute(char *cmd)
{
extern char **environ;
int exitstat = 0;
char *cmdarg[2];
cmdarg[0] = cmd;
cmdarg[1] = NULL;
exitstat = execve(cmd, cmdarg, environ);
free(cmd);
_exit (exitstat);
}
int main(void)
{
int childstat;
char *str = malloc(6);
pid_t childid;
strcpy(str, "Hello");
childid = fork();
if (childid < 0)
exit(-1);
if (childid == 0)
{
execute(str);
}
else
{
wait(&childstat);
free(str);
}
return (0);
}
当 child 进程内部有空闲时,这里是 valgrinds 结果。
当运行与child进程中的free
被注释时。(#free(cmd)
在execute函数中)。
如您所见,总体错误 (
exitstat = execve(cmd, cmdarg, environ); free(cmd), free(other passed adress);
如果成功,execve
不会return。之后没有代码执行,执行终止并启动 cmd
进程。操作系统无论如何都会释放当前进程持有的所有内存。如果 execve
调用成功,代码 free(cmd), free(other passed adress);
将不会执行 。
唯一可能与这些留置权相关的情况是 execve
错误。如果 execve
return 出现错误,是的,您应该释放该内存。我非常怀疑大多数带有 execve
的程序实际上会这样做,我相信他们只会在 execve
调用失败后调用 abort()
。
inline void execute(char *cmd)
请阅读 inline
。 inline
很棘手。我建议不要使用它,忘记它的存在。我怀疑这里的目的是制作一个内联函数——编译器无论如何都没有其他函数可以选择。修复代码中的拼写错误后,由于对 execute
的未定义引用,我无法编译代码 - inline
必须删除。
The problem here is that when the child fails to execute all the heap data remains allocated, but does that matter?
最终取决于你在child失败后想做什么。如果你只想调用 exit
并且你不关心这种情况下的内存泄漏,那么就不要关心它也没关系。
我看到 glibc exec*.c 函数尽量避免动态分配并使用可变长度数组或 alloca()
。
If my assumption is correct and this leaks doesn't actually matter, why does valgrind lament about them?
没有。如果您更正代码中的所有错误,那么 valgrind
将不会在调用 execve
之前“哀叹”内存泄漏(好吧,除非 execve
调用失败)。
Would there be a better way to free all the memories in the child heap with out actually passing all the memores (str, and the others in this example) to the execute function and laboriously call free each time?
“更好”往往是基于意见的。主观上:没有。但是 writing/using 自己的动态分配包装器和垃圾收集器来释放所有内存也是一种选择。
does kill() have a mechanism for this?
不,发送信号似乎与释放内存无关。
没有简单的解决方案。
终止时,OS 将为进程释放所有内存。这意味着您 没有 来释放所有内容。然而,对于不再需要的内存,通常最好尽快释放它。这样就留下了诸如缓冲区之类的东西,可能会一直使用到终止前的最后一刻。
释放内存的原因。
- 我只能想到一个。如果你在最后使用了大量的块,那么很难从谷壳中挑选出小麦。要么你最终得到大量无人查看的日志,要么你必须维护一个抑制文件。无论哪种方式,您都有可能忽视真正的问题。
不释放内存的原因
- 性能提升较小
- 有时候要释放所有东西是相当困难的。例如,如果您使用
putenv()
那么要知道字符串是被添加(并且需要释放)还是被替换(一定不能被释放)就有点棘手了。 - 如果您需要使用
atexit()
来释放东西,那么您可以通过atexit()
调用的函数数量是有限制的。如果您在许多模块中释放了很多东西,那可能是个问题。
我的建议是尝试释放大部分东西,但不要着急,否则你会被递减法则所困扰 returns。对于难以释放的百分之几,明智地使用抑制文件。