Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
[go: Go Back, main page]



11/11 オブジェクト・プールで倍速new&delete;

やってみましたオーバーロード


     モーなにがなんでも、とにかくやってみなきゃわかんねーっての!

     というわけで、一昨日の続き、やってみました。

     え?new演算子とdelete演算子の話ですよ。

     前回はnewとdeleteは遅い、だから使わない方がいい、という話だったんですが、よく考えたらオーバーロードできるじゃーんってことです。

     演算子のオーバーロードというのは、C++をやってないと馴染みが薄いのでおれも忘れていたというか、基本的にC++って机上の理論しか知らない(実際にそれでプログラムを組んだのは・・・うーん、クラスだのなんだのを使ったのはアステロイドファイト97くらいか)ので忘れてた。ハズカシー!ま、厚顔無恥が合い言葉のこのおれはこの程度のことではメゲない。とにかくやってみる。

     というわけで、前回のベンチマークで高速だということが立証されたストラクチャ・プールを応用して、ストラクチャならぬオブジェクト・プールというものを実装してみたってワケよ。

     原理は簡単で、まずストラクチャ・プールと同じ方式で配列をとり、その先頭アドレスで埋めたスタックを持つ。

     次に、クラス内のnew演算子とdelete演算子をオーバーロードして、ストラクチャ・プールと同じようにスタックから先頭ポインタを取得して、その値を返したり、スタックにプッシュしたりする。

     ただこれだけのことだ。

      typedef struct {
      	int data[24];
      }TStest;
      
      TStest STest[ELEMENT],*pSStack[ELEMENT],*STTest[ELEMENT];
      
      int sp;
      
      void stackInit()
      {
      	int i;
      	for ( i = 0 ; i < ELEMENT; i++){
      		pSStack[i] = &STest;[i];
      	}
      	sp=0;
      }
      
      TStest *stackPop()
      {
      	if(sp < ELEMENT-1)	return pSStack[++sp];
      	else return NULL;
      }
      
      void stackPush(TStest *s)
      {
      	if(  sp > 0){
      		sp--;
      		pSStack[sp] = s;
      	}
      }
      
      
      
      class CTest{
      	int a;
      	int b;
      	int c;
      public:
      	
      	CTest(){
      		a = b = c = 0;
      	}
      	static inline void *operator new(size_t size)
      	{
      		void *ptr;
      		ptr = stackPop();
      		return ptr;
      	}
      
      	static inline void operator delete(void *ptr)
      	{
      		stackPush((TStest *)ptr);
      	}
      };
      
     まー実際のソースでは、高速化のためにインライン関数にしたりと多少細工しているのでこのまんまではないが、実際の処理を抜き出すとだいたい上のような感じである。

     とにかく、こいつでどのくらい早くなるもんなのか、早速ベンチをやってみたが、測定条件を少し代えたので、結果的にすべてのベンチをやりなおした。
     今回は、10万個のオブジェクトまたは構造体の生成と削除を1000回繰り返すのに何秒かかったかを計った。
    関数 処理内容 処理時間
    ノーマル
    [秒]
    処理時間
    オブジェクト・プール使用
    [秒]
    bench1 なにもしない 0 0
    bench2 固定長のオブジェクトで連続してnewdeleteを交互に繰り返す 169 51
    bench3 固定長の領域で連続してmallocfreeを交互に繰り返す 143 143
    bench4 異なるサイズのクラスをランダムに確保(new)して解放(delete)を交互に繰り返す 259 94
    bench5 異なるサイズの領域をランダムに確保(malloc) して解放 (free)を交互に繰り返す 246 246
    bench6 異なるサイズのオブジェクトを不連続に確保(new) して不連続に解放 (delete)を交互に繰り返す 284 114
    bench7 異なるサイズの領域を不連続に確保(malloc) して不連続に解放 (free)を交互に繰り返す 273 273

     表でいくつかの数値が薄い色になっている理由は、オブジェクト・プールの効果と無関係だからである。ただし、前回のベンチとは測定方法が違うので、参考のために表示した。

     もはや説明の余地はないとおもうが、オブジェクト・プールを使うことによってnewとdeleteは約三倍の速度になっている。

     前回、メモリ領域は固定でとった方がよい、というようなことを言い、そして事実ストラクチャ・プールは固定領域にしか使えない方法なのだが、実はこれにはしかけがあって、今回のオブジェクト・プールは固定領域をやや大目に確保することによって、異なるサイズのオブジェクトであっても、同一の領域を割り当てることにしている。そうすることによって固定長領域になるので、異なるサイズのオブジェクトをプールで使うことができるのである。

     今回の実験も、成功と言ってよいだろう。
     これで、ようやく国後カーネルをクラス・ライブラリとして設計するうえでの心配事はあらかたなくなったわけだ。
     めでたしめでたし。