- ベストアンサー
callocの処理速度
Visual C++.netを利用しています。 確保した領域の値を0に初期化したく、自分が思いつく下記の3つの方法を試し、timeGetTime関数を用いて処理の速度を計ってみました。 結果は、Aは処理速度が1ミリ秒だったのですがBは5ミリ秒、Cは3ミリ秒もかかってしまいました。 AとB、Cに時間差が表れてしまうのはなぜなのでしょうか?また、もっと速くできる方法があるのならば教えてください。 それと、new演算子には、callocのような0で初期化されるといった機能はないのでしょうか? よろしくお願いします。 int a[100000] = {0};--------A int *a = (int*)calloc(i*sizeof(100000));------B int *a = (int*)malloc(i*sizeof(100000));------C forループで0を代入
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
質問でまだ回答していない部分があるので、もう少し・・・ まず高速化の方法ですが、ヒープ(あとでfreeを使って開放できるようなメモリ)を確保するのであれば、mallocを使ってもcallocを使っても速度は変わりません。また、これより高速にすることもできません。(「初期化しない」という選択肢が取れるのであれば、そのほうが高速にはなります。) スタック上にメモリを確保するのでも構わなければそのほうが高速ですが、確保するメモリ量とスタック領域の大きさ、それとスコープによる制限が発生します。スタック上に確保したメモリは「実行している関数内」がその確保のスコープになり、関数を抜けると自動的に開放されてしまう(ポインタが無効になる)ので、そのような条件でもよければスタック上にメモリを確保するという選択肢もあります。 new演算子のほうは、特定の値で初期化するような機能を持ってはいませんが、そのような機能を持ったnew演算子関数を作成できるはずです。(が、基本型の場合、new演算子関数はどうなるのかな・・・この辺、ちょっと分かりません。)
その他の回答 (4)
- sha-girl
- ベストアンサー率52% (430/816)
一般的にmallocは重いです。それはUNIX系でも同じです。 (またwindowsのmallocの実体はAPIのHeapAllocです。) new演算子は内部でmallocを呼んでいます。 つまりnewはmallocより更に遅くなります。 >new演算子には、callocのような0で初期化されるといった機能はないのでしょうか? new演算子だけで初期化したいなら、クラスにしてコンストラクタ内部で するしかありません。 Aはスタック上に確保していますが、スタック領域はあらかじめ 確保されている為、空き領域を探すという処理がありません。 それが処理の速い理由です。 一方mallocは、空き領域を探すという処理が入りこれが重いのです。 callocはさらに初期化が入るのでmallocより遅くなるのは当然です。 Visual C++.netのデバッカで mallocやcallocをステップインして混合モードで追えば内部で何をしているのか 見えてくるのでやってみてはどうでしょう?
お礼
回答ありがとうございます。 new演算子は結局内部でmallocを呼んでいるのですね。それだと速さを求める時はmallocの方が良さそうですね。ステップイン、混合モードは知らないのですが、調べてやってみます。 ありがとうございました。
- xcrOSgS2wY
- ベストアンサー率50% (1006/1985)
試してみました。その結果と理由付けは次のとおりです。 結果概要: 速度はAが有意に速く、BとCは同程度。 詳細: 【1: BとCの速度差に関して】 B(calloc) → free → C(malloc) → free の順で実行すればBよりCのほうが高速だが、 C(malloc) → free → B(calloc) → free の順で実行するとCよりBのほうが高速になる。この順序依存性はキャッシュによるものと考えるのが妥当である。 B(calloc)とC(malloc)では同じ量のメモリを割り当てるため、あいだにfreeを入れた前後の割り当てでは同じメモリ領域が割り当てられる可能性が高く、2回目の割り当て後のゼロクリアは高速に実行できることが期待できる。 検証のため B(calloc) → C(malloc) → free → free および C(malloc) → B(calloc) → free → free の順で実行したところ、いずれもB(calloc)とC(malloc)の実行時間はほぼ同じになった。 【2: AとB/Cの速度差に関して】 B/Cはヒープ領域からメモリの割り当てを行うのに対して、Aはスタック領域からメモリの割り当てを行う。ヒープ領域からのメモリの割り当てはメモリ割り当てリストの検索と更新を必要とするが、スタック領域からのメモリの割り当てはスタックポインタに対する単純な算術演算のみで可能でありリストの検索・更新操作を一切必要としないため、原理的に(ほとんど計測不可能なほど)高速である。 検証のためゼロクリアなしの配列変数の確保にコードを変更すると、メモリ確保自体は比較にならないほど高速であることが分かる。これはスタックからのメモリ割り当て関数allocaを用いてテストしても同様である。 なお、割り当て後のメモリクリアに要する時間は、AもB/Cも変わらない。
- qwertyf
- ベストアンサー率51% (14/27)
#1です。すいません。何か色々勘違いしてたみたいです。 calloc の方が遅いんですね。 自分でも今テストしましたがcallocは時間がかかりました。 ベストはやはり malloc で確保、memset でしょうかね。 あと、上のソースコードを見ると少しおかしな点があるのですが、 int *a = (int*)malloc( sizeof(int) * 100000 ); だと思われます。 で、その後 memset( a, 0, sizeof(int) * 100000 ); と。
お礼
早速の回答ありがとうございました。 恥ずかしながら memset を知りませんでした。 ベストな方法は malloc → memset の流れが良いみたいですね。その方法を使わせてもらいます。 ありがとうございました。
- qwertyf
- ベストアンサー率51% (14/27)
Aについて、これは配列の要素[0]のみを0で初期化しています。他の要素は0で初期化されません。早くて当然です。 B,Cでの時間差はおそらくCでforループを回して0を代入している点にあると思います。 Cでも、malloc の後に memset( a, 0, sizeof(int)*100000 ); のようにすればBと同じくらい素早く初期化できると思います。 たぶんこれ(もしくはcalloc)が最速でしょうか。 new 演算子には 0 で初期化する機能がありません。malloc と同じく、memset なりの関数で0にする必要があります。
お礼
回答ありがとうございます。 検証までしていただいて、よく分かりました。 スタック領域からの確保の方が高速になるのですね。allocaという関数を調べ、検証してみます。 ありがとうございました。