読者です 読者をやめる 読者になる 読者になる

メモリ管理コスト

.NET

C++DirectXシューティングゲーム作っていたときに,VTune のプロファイリングによってメモリ周り(new/delete)で全CPU時間の20%ぐらい食っていることが分かったときにはかなりびっくりしたなぁと遠い目.だいぶヒープを苛め抜く(ようするに何も考えていない)実装をしていたんですが,結局 CPU の速度向上がまだ期待できた時期だったのでほとんど対策せずにそのままリリースしちゃいましたけど*1
そういうわけで『IBM developerWork』の以下の記事の主張は,個人的には頷けるものがあります.

ちょっとしたクイズがあります。生のアロケーション・パフォーマンスとして速いのは、Java言語でしょうか、それともC/C++でしょうか。この答えに、多くの人は驚くでしょう。最近のJVMアロケーションは、最高パフォーマンスのmalloc実装よりも、ずっと高速なのです。HotSpot 1.4.2以降でのnew Object() 用の一般的なコード・パスは、約10マシン命令(Sun提供のデータより。参考文献を参照)ですが、Cで最高パフォーマンスのmalloc実装では、1つのコールあたり平均60から100の命令が必要です(Detlefsなどのデータによる。参考文献を参照)。しかもアロケーションのパフォーマンスは、全体的なパフォーマンスのコンポーネントとして小さなものではありません。ベンチマークによると、PerlやGhostscriptなど実世界でのCプログラムやC++プログラムでは、実行時間全体の20%から30%がmallocやfreeに費やされています。これは、健全なJavaアプリケーションでのアロケーションやガーベジ・コレクションのオーバーヘッドよりも、はるかに大きな数字です(Zornのデータによる。参考文献)。

しかし,では GC 付の言語に移行すればみんなハッピーかというとそうでもなくて,C# (が頼るところの MS CLR) の GC にしても,「C# ではメモリ管理について考えなくて良くなる」というのはヘジたんの言うところの「カプセル化の目的の誤解」であって,より信頼がおけるのは「仕組みを理解したうえで楽をするために GC が組み込まれている言語」という見方かと思います.
1つの試金石は「C++C# どちらが優れたメモリ管理を行うか?」というディベートでどちらの陣営に経った場合でも,それぞれの長所を生かした効果的な(説得力のある)サンプルコードを提供できるかどうかでしょう.両方が想定出来てこそ,戦場をどこに定めるかといった楽しみが出てきます.
ベンチマークに関する FUD は尽きませんが,ディベートの練習と思って楽しむ余裕は欲しいところですね.
% Time in GC
画像は C# 2.0 で書かれたレイトレースプログラムについて,パフォーマンスカウンタが示す「GC に使用した時間割合 (% Time in GC)」.Typical な値を普段から注意して見ておいた方がいざというとき問題に気付きやすい.

*1:_aligned_malloc がそこそこ時間を食っていて,そいつは行列確保と分かっていたので,行列に関してのみ独自のメモリアロケータを書いてみたら,特定シーンでのCPU時間は10%ぐらい下がりましたけど