在父级中的malloc之后的fork ...子进程是否需要释放它?

时间:2014-05-03 04:08:57

标签: c dynamic malloc fork execvp

回答你头脑中的问题:是的,这是针对学校的。不,我不能使用线程。是的,我寻找答案,有些人说“是”,其他人则说“不”。我也正在检查我的教授,因为如果其他人要对其进行评分并且他们要求“修复”,我不想不公平地失分。

有了这样说......在Linux系统上考虑这个简单的c程序。我malloc的东西,然后叉。我把我的项目归结为确切的问题:

#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 directory\n", 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: %i\n", WEXITSTATUS(status));
        }
    }

    free(something);
    return 0;
}

现在这是令人困惑的地方。据我所知,fork在该特定状态(包括文本,数据等)创建父进程的精确副本。我在某处读到这包括任何malloc'd(所以,堆)。但是,我在其他地方读到它并不是因为所谓的“写时复制”,但后来在其他地方读到“写时复制”只是一种透明且无关紧要的优化。但那时我读到的最有意义的是,因为它是一个COPY,它有它自己的,好的......一切。

但后来我记得当使用fork()时,malloc所包含的内容将包含相同的内存地址,父和子指向相同的内容也是如此?我是否还需要释放孩子的资源?是仅复制了指针,还是指针指向的数据也被复制了?

我使用了valgrind,当子进程退出时,它只是抱怨所有内存仍然可以访问。究竟是什么“仍然可以到达?”它“仍然可以到达”的事实是否能回答我的问题,并说父母和孩子指的是同一个事情而父母是唯一一个负责释放记忆的人?

3 个答案:

答案 0 :(得分:4)

如果没有致电exec家人,您必须free()。父和子不指向同一个东西,因为它们是独立的进程,并且不共享相同的地址空间。想象一下,如果父亲free()例如,然后孩子试图访问它,会在替代方案下发生什么。

如果您确实调用execvp()之类的内容,那么就像tmyklebu所提到的那样,您的流程就会被删除,而您无需做任何事情。

“仍然可以访问”意味着您仍然可以参考它,但您还没有free()它。因为无论如何你的所有内存都会在终止时获得free() d,这与获得实际的内存泄漏相比,有时并不是一个问题,因为你会永久地忘记已分配的内存。 Valgrind's FAQ本身说“你的程序可能没问题 - 它没有释放它可能拥有的一些记忆。这是很常见的,而且往往是合理的。”关于这个问题的意见有所不同 - 有些人说这是明确地释放()所有内容的好形式,其他人说这是一种毫无意义的资源浪费,无法完成程序终止为你自己做的事情。

答案 1 :(得分:3)

execvp擦除了你的地址空间,因此分配的内存消失了。

_exit退出程序,意味着已分配的内存消失。

您不需要在子进程中明确free任何内容;事实上(因为COW的事情)这样做并不是一个好主意。

答案 2 :(得分:2)

free之前调用execvp毫无意义,它实际上使您的代码不再可重用/可移植,因为在{{{{}}之后调用free无效1}}如果调用进程是多线程的。