0

どうしても解決できない状況があります。ゆっくりと、しかし時間が経つにつれて悲惨なメモリリークを引き起こしています。ポインターの構造 (関数に渡したもの) を解放しているにもかかわらず、それらの内部のポインターを解放するのを忘れていたことに気付きました。valgrind によると、メモリ リークが発生します。関数内からポインタのメモリを解放しようとしましたが、エラー メッセージを解決できないようですerror: request for member 'xxx' in something not a structure or union

これは私のプログラムの簡単な概要です。スレッド関数に必要な変数を保持するデータ構造を作成しています。引数が渡されるメイン関数があり、データに応じて適切な構造体に入力されます。次に、実際の関数のスレッドを起動し (構造体を void ポインターとして渡します)、関数内の実際の構造体を取得して再作成します。これはコードです:

void cmd_test(char *sender, char **args, int arg_count) {
    char command[1024];

    // creates my exec pointer structure
    exec_struct *exec = malloc(sizeof(exec_struct));

    // adds a thread identifier to a struct to keep track of threads
    exec->tID = thread_add(EXEC);

    // the first malloc which I don't know how to free
    exec->sender = malloc(sizeof(char) * strlen(sender) + 1);
    sprintf(exec->sender, "%s", sender);

    // move ahead 5 arguments (there will always be 5 or more arguments supplied
    // by the calling function)
    args += 5;
    memset(command, 0, sizeof(command));

    // concatenate the remaining arguments into a cstring
    while(*args[0]) {
        printf("arg: %s\n", *args);
        sprintf(command, "%s %s", command, *args);
        args++;
    }

    // the second malloc which I don't know how to free
    exec->exec = malloc(sizeof(char) * strlen(command) + 1);

    // copy the string to the structure from pointer+1 to end of pointer
    // removes a space created from the first iteration of previous loop)
    sprintf(exec->exec, "%s", command + 1);

    printf("command:%s\n exec:%s\n", command, exec->exec);

    //stores an actual thread id into a struct of threads to keep track of 
    //the actual thread (other one is just to keep track of what type
    //of thread is running)
    threads[exec->tID].tID = Thread_Start(exec_cmd, exec);
}

これが、何が起こっているのかについてのコメントを付けて構造をセットアップする方法です。Thread_Start()スレッド化された関数に渡す関数アドレスと構造体アドレスを受け入れる単なる関数です。これはexec_cmd機能です:

void *exec_cmd(void *param) {
    char buf[1024];
    FILE *command;

    // recreate the structure locally inside the thread
    exec_struct exec = *((exec_struct *)param);

    // causes the error described
    // free(param.exec);
    // free(param.sender);

    // free the structure memory from the thread creating function.
    free(param);

    memset(buf,0,1024);
    sprintf(buf,"%s",exec.exec);
    command = popen(buf,"r");

    while(!feof(command)) {
        memset(buf,0,1024);
        fgets(buf,1024,command);
        printf("%s\n", buff);
        sleep(1);
    }

    pclose(command);

    // cleans itself up from the tracking structures
    thread_remove(EXEC, 0);

    // exits cleanly
    return NULL;
}

エラーを解決するために、その前に構造をキャストしようとしましたが、エラーは引き続き発生します。->演算子を使用すると、void* deferenceエラーが発生します。

また、スレッドが既に実行されているかどうかを確認するチェックや、煩雑さを軽減するためのエラー チェックなど、関数からいくつかの大部分を削除しました。関数は両方とも私のアプリケーションで機能します(スレッドを作成して正常に保存し、新しい構造を完全に渡して作成し、渡されたコマンドを実行しています)。スレッド内から行った 2 つの malloc 呼び出しを解放する方法がわかりません。この問題を解決するにはどうすればよいですか?

4

2 に答える 2

2
exec_struct exec = *((exec_struct *)param);

//free(param.exec);
//free(param.sender);

param がvoid *渡されます。構造体のコピーは と呼ばれexecます。

あなたはおそらく次のことを意味していました:

free(exec.exec);
free(exec.sender);

exec.execただし、後で同じ関数にすぐにアクセスすることに注意してください。すでに解放されている場合は、それを行うことはできません。構造体をコピーしても、ポインターが指すメモリをコピーしたわけではありません。

この行:

sprintf(buf,"%s",exec.exec);

解放される前に発生する必要exec.execがあります。

于 2012-12-25T00:16:02.843 に答える
0

一般的な原則は、構造の「最も深い」レベルから始めて、上に向かっていくことです。内部のすべてが解放されるまで、「上位」レイヤーにあるものを決して解放しないでください。つまり、malloc を呼び出した順序とは逆の順序を使用します。

私は本当にやる意味がわかりません:

exec_struct exec = *((exec_struct *)param);

元のポインターをコピーするだけです。

exec_struct *exec = (exec_struct *)param;

それで

free(exec->sender); 
free(exec->command);

free(exec);

もちろん、exec 構造の使用が終了するまでは、解放を行うべきではありません。

于 2012-12-25T00:59:47.900 に答える