回答你脑海中的问题:是的,这是为了上学。不,我不能用线程。是的,我在寻找答案,有些人说"是",有些人说"不是"。我也会核实我的教授的事实,因为我不想在别人给我评分时不公平地失分,因为他们要求"修正"这个错误。"
话虽如此……考虑在Linux系统上用c编写这个简单的程序。我把东西放进去,然后分叉。我把我的项目归结为具体的问题:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int main( void )
{
char * args [] = { "someinvalidcommand", NULL };
// malloc before the fork (happens in parent process)
char * something = (char *)malloc(sizeof(char));
pid_t child_pid = fork();
// are there now two things that need to be freed:
// one for each process?
if(child_pid == 0) // child process
{
//free(something); // is this needed?
// execvp (it won't return if succeeded)
if(execvp(args[0], args) < 0)
{
// or do I only need to free it here?
printf("%s: No such file or directoryn", args[0]);
/*
* EDIT: Calling it here seems to fix the issue. It turns out
* that the system calls were the ones with the "still reachable"
* errors, so I guess it's not all that important that the
* memory be freed.
*
* free(something)
*/
_exit(1);
}
}
else // parent process
{
int status;
while(wait(&status) != child_pid);
if(status != 0)
{
printf("command status: %in", WEXITSTATUS(status));
}
}
free(something);
return 0;
}
这里有点令人困惑。据我所知,fork创建了父进程在特定状态下的精确副本(包括文本、数据等)。我在某处读到,这包括任何malloc'd(所以,堆)。然而,我在其他地方读到,它不是因为所谓的"写时复制",但后来我在其他地方读到,"写时复制"只是一种透明和无关紧要的优化。但后来我读到的最有意义的是,因为它是一个拷贝,它有自己的,嗯……一切。
但是我想起来,当使用fork()时,无论malloc是什么,都将包含相同的内存地址,所以父节点和子节点指向相同的东西吗?我是否也需要在子进程中释放资源?只是复制了指针,还是指针所指向的数据也被复制了?
我使用了valgrind,当子进程退出时,它只是抱怨所有的内存仍然是可访问的。它到底是怎么"还能联系到"的?事实是,它是"仍然可达"回答我的问题,说父和子都指向相同的东西和父的唯一负责释放内存?
在没有呼叫exec
家族的情况下,您必须free()
它。父进程和子进程不指向相同的东西,因为它们是独立的进程,不共享相同的地址空间。想象一下在另一种情况下会发生什么,例如,如果父母free()
设置它,然后孩子试图访问它。
如果您调用execvp()
之类的东西,那么正如tmyklebu提到的,您的进程就会被擦除,而您不必做任何事情。
"Still reachable"意味着你仍然有一个对它的引用,但是你还没有free()
d它。由于在终止时所有的内存都会获得free()
d,因此与永久丢失已分配内存的实际内存泄漏相比,这有时并不是什么大问题。Valgrind的FAQ说:"你的程序可能没有问题——它没有释放一些内存。这很常见,也很合理。"对这个问题的看法各不相同——有些人说显式地free()所有东西是一种好形式,另一些人说这样做是毫无意义的资源浪费,因为程序终止本身将为您做所有的事情。
execvp
擦除您的地址空间,因此已分配的内存将消失。
_exit
退出程序,表示分配的内存已经用完了。
你不需要显式地在子进程中设置free
;事实上(因为COW的事情)这样做并不是一个好主意。
在execvp
之前调用free
是没有意义的,它实际上使你的代码更不容易重用/可移植,因为如果调用进程是多线程的,在fork
之后的子进程中调用free
是无效的。