Fork nach Malloc im Elternteil … muss der Kindprozess es befreien?

Lesezeit: 6 Minuten

Benutzer-Avatar
Benutzer3598200

Antworten auf Fragen im Kopf: Ja, das ist für die Schule. Nein, ich kann dafür keine Threads verwenden. Und ja, ich suchte nach einer Antwort und einige Leute sagten “ja” und andere sagten “nein”. Ich überprüfe auch die Fakten meines Professors, weil ich nicht unfairerweise Punkte verlieren möchte, wenn jemand anderes es benoten würde und sie verlangen, dass dies “korrigiert” wird.

Betrachten Sie dieses einfache Programm für c auf dem Linux-System. Ich mallociere etwas und forke dann. Ich habe mein Projekt auf das genaue Problem reduziert:

#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;
}

Hier ist es jetzt etwas verwirrend. Meines Wissens erstellt Fork eine exakte Kopie des übergeordneten Prozesses in diesem bestimmten Zustand (einschließlich Text, Daten usw.). Ich habe irgendwo gelesen, dass dies alles enthält, was malloc’d ist (also den Haufen). Ich habe jedoch an anderer Stelle gelesen, dass dies aufgrund von etwas namens “Copy-on-Write” nicht der Fall ist, aber dann habe ich an anderer Stelle gelesen, dass “Copy-on-Write” einfach eine Optimierung ist, die transparent und irrelevant ist. Aber was ich dann am sinnvollsten gelesen habe, war, dass es, da es sich um eine KOPIE handelt, sein eigenes, na ja … alles hat.

Aber dann erinnere ich mich, dass bei Verwendung von fork() alles, was mallociert wurde, dieselbe Speicheradresse enthält, also zeigen Eltern und Kind auf dasselbe? Muss ich auch beim Kind Ressourcen freisetzen? Werden nur die Pointer kopiert oder werden auch die Daten kopiert, auf die die Pointer zeigen?

Ich habe valgrind verwendet und wenn der untergeordnete Prozess beendet wird, beschwert er sich einfach, dass der gesamte Speicher noch erreichbar ist. Wie genau ist es “noch erreichbar”? Beantwortet die Tatsache, dass es “immer noch erreichbar” ist, meine Frage und sagt es, dass Elternteil und Kind auf dasselbe zeigen und der Elternteil der einzige ist, der für die Freigabe des Speichers verantwortlich ist?

  • Dieser Thread erklärt, stackoverflow.com/questions/4597893/…

    – MM

    3. Mai 2014 um 4:17 Uhr

  • Ich würde vorschlagen, Ihr Betriebssystem in Ihren Kommentar oder Ihre Tags einzufügen

    – MM

    3. Mai 2014 um 4:22 Uhr

Benutzer-Avatar
Krähenmann

In Ermangelung der Anrufe an die exec Familie, du musst free() es. Parent und Child zeigen nicht auf dasselbe, da sie separate Prozesse sind und nicht denselben Adressraum teilen. Stellen Sie sich vor, was unter der Alternative passieren würde, wenn der Elternteil free()d es zum Beispiel, und dann versuchte das Kind, darauf zuzugreifen.

Wenn Sie so etwas anrufen execvp()dann wird, wie tmyklebu erwähnt, Ihr Prozess einfach gelöscht, und Sie müssen nichts tun.

“Noch erreichbar” bedeutet, dass Sie immer noch einen Verweis darauf haben, aber Sie haben keinen free()d es noch. Da bekommt Ihr ganzes Gedächtnis free()d bei der Beendigung sowieso, ist dies manchmal kein so großes Problem, verglichen mit einem tatsächlichen Speicherleck, bei dem Sie dauerhaft den Überblick über den zugewiesenen Speicher verlieren. Valgrinds FAQ selbst sagt, dass “Ihr Programm wahrscheinlich in Ordnung ist – es hat keinen Speicher freigegeben, den es haben könnte. Dies ist ziemlich üblich und oft vernünftig.” Die Meinungen zu diesem Thema gehen auseinander – einige Leute sagen, es sei eine gute Form, alles explizit free() zu machen, andere sagen, es sei eine sinnlose Verschwendung von Ressourcen, das zu tun, was die Programmbeendigung von selbst für Sie tun wird.

  • Du verstehst nicht wie fork funktioniert. Wenn die Eltern frees ein Objekt post-fork, existiert das Mapping immer noch im untergeordneten Prozess und das Mapping bezieht sich auf eine Kopie des Objekts zum Zeitpunkt des fork.

    – tmyklebu

    3. Mai 2014 um 4:16 Uhr

  • @tmyklebu: Genau das habe ich gesagt. “Elternteil und Kind zeigen nicht auf dasselbe … Stellen Sie sich vor, was unter der Alternative passieren würde.”

    – Krähenmann

    3. Mai 2014 um 4:18 Uhr


  • Erwischt. Sie gehen davon aus, dass OP keinen zugewiesenen Speicher zum Zeitpunkt von erreichen möchte exec. Ihre Antwort macht in diesem Zusammenhang Sinn.

    – tmyklebu

    3. Mai 2014 um 4:20 Uhr


  • Sie “müssen” nie etwas freigeben.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    3. Mai 2014 um 5:24 Uhr

  • Du musst sie befreien, wenn du willst, dass sie befreit werden. Der Kontext der Frage ist eindeutig, muss das Kind sie befreien, oder werden die Eltern sie für Sie befreien? Und die Antwort ist nein, die Eltern geben sie nicht für das Kind frei, wenn Sie wollen, dass sie frei im Kind sind, muss das Kind sie freigeben.

    – Krähenmann

    3. Mai 2014 um 5:38 Uhr

execvp löscht Ihren Adressraum, sodass der zugewiesene Speicher weg ist.

_exit beendet Ihr Programm, was bedeutet, dass der zugewiesene Speicher weg ist.

Sie müssen dies nicht explizit tun free irgendetwas im untergeordneten Prozess; Tatsächlich ist es (wegen der COW-Sache) keine gute Idee, dies zu tun.

  • Sie scheinen das im Grunde zu sagen, da das Betriebssystem alles freigibt, wenn _exit passiert sowieso, OP sollte sich keine Gedanken über die Freigabe von Sachen machen.

    – MM

    3. Mai 2014 um 4:19 Uhr

  • @MattMcNabb: Ja. Außerdem möchten Sie nicht in den Speicher schreiben, den Sie nicht berühren müssen (da dies eine Kopie verursacht). freeing Ihre Zeiger vor einem exec ist ein Lesbarkeits- und Performance-Hit ohne Gewinn.

    – tmyklebu

    3. Mai 2014 um 4:22 Uhr

  • Was ist, wenn Sie den untergeordneten Prozess für eine Weile ohne exec() beibehalten und mehr oder weniger unabhängig vom übergeordneten Prozess arbeiten?

    – SamB

    6. September 2016 um 21:41 Uhr

  • @SamB: Dann wird das Betriebssystem jedes Mal, wenn entweder ein Elternteil oder ein Kind auf eine Seite schreibt, die es vorher nicht hatte, eine Menge kopieren. Das heißt, Sie sehen wahrscheinlich einen erheblichen Leistungseinbruch. Warum würden Sie das tun wollen?

    – tmyklebu

    9. September 2016 um 5:23 Uhr

Berufung free Vor execvp ist sinnlos, und es macht Ihren Code tatsächlich weniger wiederverwendbar/portabel, da es nicht gültig ist, ihn aufzurufen free beim Kind danach fork wenn der aufrufende Prozess multithreaded ist.

  • Eh? Nicht gültig wie?

    – SamB

    6. September 2016 um 21:41 Uhr

  • @SamB: Für einen Multithread-Prozess, der sich verzweigt, dürfen nach der Verzweigung nur asynchronsignalsichere Funktionen im untergeordneten Element aufgerufen werden. Der Aufruf einer async-signal-unsafe-Funktion führt zu undefiniertem Verhalten.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    7. September 2016 um 3:32 Uhr

  • Oh, ich verstehe, POSIX ist eigentlich der Grund dafür ziemlich prägnant: Suchen Sie nach “* Ein Prozess soll mit einem einzigen Thread erstellt werden. […]” an pubs.opengroup.org/onlinepubs/9699919799/functions/fork.html

    – SamB

    9. September 2016 um 1:14 Uhr

  • @SamB: Ja. Konzeptionell, da der Speicher im untergeordneten Element aus einem momentanen Zustand des übergeordneten Elements stammt, in dem sich andere Threads möglicherweise mitten in asynchronen signalunsicheren Funktionen befunden haben, und da diese Threads nicht mehr vorhanden sind, um Fortschritte zu erzielen, die Umgebung des untergeordneten Elements ähnelt dem, was Sie erhalten würden, wenn Sie von einem Signal-Handler abzweigen würden, der diese AS-unsicheren Funktionen unterbrochen hat.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    9. September 2016 um 1:40 Uhr

1153040cookie-checkFork nach Malloc im Elternteil … muss der Kindprozess es befreien?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy