malloc
とcalloc
の違いは、表面的には引数の数とcalloc
は確保した領域を0で初期化するという点くらいですが、以下のコードを大きなn
で実行すると、今時のOSだとmalloc
+ memset
のほうが大幅に遅くなる可能性があります。
void *p = malloc(n * sizeof(type)); memset(p, 0, n * sizeof(type));
void *p = calloc(n, sizeof(type));
カーネルはセキュリティ上の理由からメモリを0で初期化してからユーザプロセスに渡します。
しかし、仮想メモリをサポートしたシステムでは、実際にそのメモリに書き込みが発生するまでカーネルはread onlyな領域を複数プロセスで共有させることができるため、既に初期化してあるページであればこの処理を省略できる場合があります。
brk
で拡張した領域は0で初期化されているので、calloc
は新規確保した領域は初期化を省略することができ、結果的にcalloc
を実行したタイミングでは初期化が実際にはほとんど発生しない、ということがありえます。
一方memset
の場合は実際にメモリへの書込みが発生する上、ページの共有もできなくなるためswapする可能性もあります。
ちなみに、(カーネルではなく)calloc
自身が0初期化する処理と、memset
の処理は微妙に違います。
なぜなら、memset
は対象の領域がアラインされているかどうかについての情報なしに処理する必要があるので、境界部分は1byteずつやるしかありません。
じゃあmemset
のほうが遅いのかというと、コンパイラによってはアラインされていることを推測できる場合もあったり、callocはライブラリ関数なので移植性のために最適化しにくかったりするので、結局のところ微妙です。
参考: http://stackoverflow.com/questions/2688466/why-mallocmemset-is-slower-than-calloc
]]>