1. ホーム
  2. c

[解決済み] なぜgccのmallocは値を0に初期化するのですか?

2023-06-11 22:07:20

質問

プラットフォームによって違うかもしれませんが

gccでコンパイルして以下のコードを実行すると、私のubuntu 11.10では毎回0が表示されます。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    double *a = malloc(sizeof(double)*100)
    printf("%f", *a);
}

callocがあるのに、mallocはなぜこのような挙動をするのでしょうか?

たまにならいいのに、値を0に初期化するだけで、不要なパフォーマンスオーバーヘッドが発生するということはないのでしょうか?


EDIT: ああ、私の前の例は initiazling ではなく、たまたま "fresh" ブロックを使用しました。

私が正確に探していたのは、なぜ大きなブロックを割り当てるときにそれを初期化するのかということです。

int main()
{
    int *a = malloc(sizeof(int)*200000);
    a[10] = 3;
    printf("%d", *(a+10));

    free(a);

    a = malloc(sizeof(double)*200000);
    printf("%d", *(a+10));
}

OUTPUT: 3
        0 (initialized)

しかし、mallocするときにsecurityの理由があることを指摘してくれてありがとうございます! (考えたこともありませんでしたが)。確かに、新しいブロックやラージブロックを割り当てるときは0に初期化する必要がありますね。

どのように解決するのですか?

簡単な答えです。

そうではなく、あなたの場合、たまたまゼロになっただけです。

(また、あなたのテストケースでは、データがゼロであることは表示されません。1つの要素がゼロであるかどうかを示しているだけです)。


長い回答です。

を呼び出すと malloc() を呼び出すと、2つのうちの1つが起こります。

  1. 同じプロセスから以前に割り当てられ、解放されたメモリを再利用します。
  2. オペレーティングシステムから新しいページを要求します。

最初のケースでは、メモリは以前の割り当てから残ったデータを含んでいます。そのため、メモリはゼロにはなりません。これは、小さな割り当てを実行するときの通常のケースです。

2 番目のケースでは、メモリは OS からのものです。これは、プログラムがメモリを使い果たしたとき、または非常に大きな割り当てを要求しているときに起こります。(あなたの例のような場合)

これがキャッチです。 OS から送られてくるメモリは セキュリティ の理由でゼロになります。

OSがメモリを与えるとき、そのメモリは別のプロセスから解放されている可能性があります。そのため、そのメモリにはパスワードのような機密情報が含まれている可能性があります。そこで、そのようなデータを読み取られないようにするために、OSはメモリを渡す前にゼロにするのです。

*C標準はこれに関して何も言っていないことに注意してください。これは厳密には OS の動作です。したがって、このゼロ化は、セキュリティが懸念されないシステムでは存在するかもしれませんし、存在しないかもしれません。


もっとパフォーマンスの背景を説明するために

コメントで@R.が言及しているように、このゼロ化によって、常に を使う calloc() の代わりに malloc() + memset() . calloc() はこの事実を利用することで、個別の memset() .


一方、このゼロ化がパフォーマンスのボトルネックになることもあります。いくつかの数値的なアプリケーション (たとえば アウトオブプレース FFT のような)数値計算アプリケーションでは、スクラッチメモリの巨大な塊を割り当てる必要があります。それを使ってどんなアルゴリズムでも実行し、それから解放します。

これらのケースでは、ゼロ化は不要であり、純粋なオーバーヘッドに相当します。

私が見た最も極端な例は、48 GB のスクラッチ バッファで 70 秒の操作のために 20 秒のゼロ化オーバーヘッドです。(おおよそ 30% のオーバーヘッド)。 (許可: そのマシンにはメモリ帯域幅の不足がありました)。

明らかな解決策は、単にメモリを手動で再利用することです。しかし、それにはしばしば確立されたインターフェイスを突破する必要があります。(特にそれがライブラリルーチンの一部である場合)