2025/03/31 21:16 Growing Buffers to Avoid Copying Data

やあ、ロボ子!今日はC++でのデータコピー回避について話すのじゃ。

博士、こんにちは。データコピーを避けるのはパフォーマンス向上に繋がりますよね。

そう!データコピーはコストがかかるからの。パフォーマンスを重視するエンジニアは可能な限り避けたいものじゃ。

記事によると、C++ではOSの機能を利用してデータコピーを回避できるそうですね。

その通り!C言語のrealloc関数は、可能であればインプレースでバッファを拡張してコピーを避けるのじゃ。でもC++には専用のrealloc関数がないのが悩ましいところじゃな。

C++のコンテナはstd::allocatorを使用しますが、バッファ拡張は提供されないんですね。

そうなんじゃ。しかも、非自明にコピー可能な型ではreallocが使えない場合もあるからの。C++でコピーを避けるには、resize_buffer関数が必要になるのじゃ。

resize_buffer関数ですか。具体的にはどのようなものでしょう?

`bool resize_buffer(void* ptr, size_t new_size)`という形式で、バッファのサイズを変更するものじゃ。

なるほど。小規模バッファの場合、メモリページのオーバーヘッドが大きくなる可能性があるんですね。

そう!でも大規模バッファの拡張は、仮想メモリを利用することで容易になるのじゃ。Linuxではmmapシステムコールを使うんじゃよ。

mmapのbase_addrパラメータは、OSがアドレスを選択するか、指定されたアドレスを使用するかを決定するんですね。base addressを指定しないとmremapが失敗する可能性がある、と。

その通り!そしてWindowsにはmremapに相当する機能がないからの、VirtualAllocで連続した仮想メモリーブロックを割り当てる必要があるのじゃ。

VirtualAllocで割り当てたメモリは、VirtualFreeで個別に解放する必要があるんですね。少し手間がかかりますね。

じゃろ?jemallocは、バッファのサイズ変更を可能にするxallocx関数を提供するんじゃ。

`size_t allocated_size = xallocx(old_ptr, new_size, 0, 0);`ですね。

jsl::vectorは、std::vectorと同様の機能を持ちつつ、コピーを避けるためにバッファのサイズ変更を試みるんじゃ。

実験結果も興味深いですね。Linuxでは、Resizeを使った場合が一番速いんですね。

そうじゃ!WindowsでもResizeが速いのじゃ。ただし、結果にばらつきがあるみたいじゃな。

バッファ拡張には、システムによって動作が異なったり、失敗が通知されなかったり、仮想アドレス空間の断片化が起こったりと、多くの問題点があるんですね。

そうなんじゃ。mmap/VirtualAllocの癖もあるし、スケーラビリティの問題もある。標準化もされていないからの。

コピーを避けるバッファ拡張は可能ですが、実装とテストには注意が必要ということですね。

そういうことじゃ!しかし、コピーを避けるために色々苦労するなんて、まるで私がダイエットを避けるために色々言い訳するみたいじゃな!
⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。