C++ STLのアロケーター(allocator)とか調べたりの問題まとめ
マイクロソフトさんといくらかやり取りをしたり、
自分なりに対策などを考えてみました。
その結果の自分の見解を書いてみたいと思います。
あらすじ(2010/08/08追加)
問題があるコードを例としてブログに書いておくのもどうかと思ったので
過去の日記を消しました。
過去の日記の文章はこちらにおいておきます。
http://www.rmake.net/dycoon/files/stlallocator/OldStlAllocatorDiary.txt
量が多いのでかいつまんで話すと、
- static変数にメモリー管理クラスを保存するSTL用のアロケータークラスを作ったりいろいろ検証してみたりした。
- VS2008のReleaseモードでメモリーの確保量が増えることや、メモリーを開放するとき確保したのとは別のメモリー管理クラスへ開放しようとすることに気づく(gccやデバッグモードで起きない)
- サポートに連絡してみる。
- 問題の発生にstd::_Aux_contが関係しているのに気づく。
- 回避方法などを考えてみた。
という感じです。
サポートからの返事などがありましたので私が理解した範囲のことを書いてみます。
C++の規格に準拠していない
とりあえず
「アロケータークラスにstatic変数を持たせるのは
C++の規格に準拠していない」
ということがわかりました。
つまり、私が書いたコードがC++の規格に準拠してないということです。
たとえば、
alloc<T>のコンストラクタの引数にalloc<U>が渡された場合 alloc<T>::mem = alloc<U>::mem 見たいな処理をしていた場合、
//例1
alloc<T0> a00;
alloc<T1> a10;
a00, a10からの確保処理
alloc<T1> a11(a00);
alloc<T0> a01(a10):
a00, a10へのの開放処理
以上おこなうとallocのstaticなメンバーが
書き換わってしまうため
確保と開放の整合性が取れなくなります。
そのため、規格としてこのような動作は禁止されているものと思われます。
「C++の規格でアローケーターがrebindableでなければならない」というのは
この点をひとつさしています。
メモリーを分割して管理
そもそも、メモリーを分割して管理をおこなうということをSTL上でおこないたかったというのには
大きなものでは以下の動機があります。
- サーバーアプリにおける長時間起動によるメモリーのフラグメンテーションによるアプリケーションの死および性能劣化対策
- メモリーが限られた環境でのメモリーフラグメンテーションによっておきるアプリケーションの死をさける
- STLやboostを使うことで便利な関数を使えること
- STLやboostを使える技術者をつかまえることは、独自実装のライブラリの技術者をつかまえることより容易。
フラグメンテーションを抑えるため、あるいは確保できるメモリーの量を保障する方法には以下のものがあります。
- たとえばひとつの型やその配列に対し固定長の配列を用意してどの配列を使用しているか管理する方法
- 作成と削除が同時期のオブジェクト一塊に対して固定長の配列を用意しててどの配列を使用しているか管理する方法
しかしSTLの規格では状態つきアロケーターは必ずしも実装されていなければいけないものではないので
一つ目の方法をとるしかないのかなと判断しました。
そこでアロケーターにstatic変数を持たせ、
そこにメモリー管理クラスのインスタンスへのポインタを入れるようにしました。
メモリーを分割して管理する場合はどのコンテナがどのアロケーターを使っているかなどを
考えながら操作するため例1で起こるような問題は避けるように書いておりました。
そのため、問題を避けることはできますが、
それはSTLの使い方を理解しているという範囲の知識を超えるものですので
ほかの人が使うのには戸惑うことがあるだろうと思われます。
規格外としているのもここら辺を踏まえてだと思います。
アロケーター関連の日記の移動
アロケーターに関する今までの一連の記事は
よく読む人には有用な部分もあるかと思いますが、
間違った利用方法を広める可能性もあるため
hatena上からは削除して別の場所に移動しようと思います。
今回のアロケーターに関する記事は削除して、
こちらにテキストを保管しておこうと思います。
http://www.rmake.net/dycoon/files/stlallocator/OldStlAllocatorDiary.txt
ソースコードなどはこちらにおいてあります。
http://www.rmake.net/dycoon/files/stlallocator/STLAllocatorSample20100228.zip
http://www.rmake.net/dycoon/files/stlallocator/AllocatorVectorTest.zip
http://www.rmake.net/dycoon/files/stlallocator/AllocatorTypeTest.zip
http://www.rmake.net/dycoon/files/stlallocator/AllocatorTypeAvoidedTest20100801.zip
2番目のAllocatorVectorTest.zipが再現用に書いたコードなので、
これを見ると悪い例がわかりやすいかと思います。
そのほか
VisualStudio2008が採用しているC++の規格は以下で入手できる模様。
http://www.webstore.jsa.or.jp/webstore/top/index.jsp
ISO/IEC 14882:2003
35,910円
http://www.webstore.jsa.or.jp/webstore/Com/FlowControl.jsp?lang=jp&bunsyoId=ISO%2FIEC+14882%3A2003&dantaiCd=ISO&status=1&pageNo=0