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

methaneのブログ

このブログに乗せているサンプルコードはすべてNYSLです。

初期化されないメモリ空間確保が必要

stream(ファイル、socket、他にももろもろな、stream型のi/o)からinputするときの受信バッファとして、「最大でN[byte]必要ってことはわかってるんだけど、実際にはNよりずっと少ないことが多い」という場面は良くある。
で、仮想メモリ空間の広さに比べてNが十分に小さいとき(32bitなら数百MB程度)、全部mallocで確保してしまって、先頭から順に使うという富豪的プログラミングが可能だ。

しかし、初期化されないバッファの確保ができない言語の場合は、大容量バッファの確保には多大なコストがかかってしまう。たとえば、バッファが0で初期化される場合、どうせファイル読み込むのに無駄に0で初期化する・・・だけの問題ではない。
malloc()でN[byte]確保したときには、仮想メモリ空間だけを確保していて、実メモリは使用していない。だから、数百MB確保して実際には数十KBしか使わなかった場合、バッファの先頭の数十KBの領域だけに実メモリが割り当てられ、使用される。
それに対して、Javaのbyte[]のように初期化があると、初期化時に数百MBのページがすべて実メモリにマップされてしまう。メモリに余裕が無かったら、せっかくOSが持ってたディスクキャッシュが消えてしまうし、メモリが足りなかったらいちいちスワップまでしてしまう。どうせ数十KBしか使わないのに。

あー、JavaC#だけの問題じゃなかった。vector buff(N); も同罪。C++にはにget_temporary_buffer()*1というのもあるけど、これはデストラクタで自動的にfreeしてくれていたりするわけでは無くて、自分でreturn_temporary_buffer()しないといけないから、malloc()と大して変わらない。むしろ、realloc()がある分、malloc()の方が良いかも。

*1:http://www.sgi.com/tech/stl/get_temporary_buffer.html