私はかなり前にオブジェクト プーリング システムを作成しました (そのほとんどは、当時必要だった部分だけです)。プログラムが進化した今、プールを実装したときにはなかったと思われる欠陥を発見しました。
基本的に、プールはオブジェクトをコンストラクターとして受け取り、それをリフレクションで複製して、そのオブジェクトの配列を作成します。プールにオブジェクトを作成する関数の実装は次のとおりです。
poolSize i = 0;
T[] oldData = null;
if (this.chunks != null && this.chunks.Length > 0)
{
oldData = new T[this.depth];
Array.Copy(this.chunks, oldData, this.chunks.Length);
}
this.chunks = new T[this.depth + this.depthIncrement];
if (oldData != null)
{
Array.Copy(oldData, this.chunks, oldData.Length);
}
for (i = this.depth; i < this.depth + this.depthIncrement; i++)
{
this.chunks[i] = Cloner.CloneObjectWithIL(this._template);
this.freeQueue.Add(i);
}
this.depth += this.depthIncrement;
ここで、Object.ReferenceEquals(pool.chunks[0], pool.chunks[1]) をチェックすると false が返されます。したがって、配列の各インデックスは、1 つのオブジェクトへの単なる参照の集まりではなく、独自のオブジェクトであるように見えます。
メイン コードでは、GetObject メソッドを使用して、プールからオブジェクトをフェッチします。
public T GetObject(T tmp)
{
T retObj = tmp;
this.chunks[this.volume] = retObj;
this.usedQueue.Add(this.volume);
this.volume++;
return retObj;
}
保護されたメモリ エラー (C# で SEGFAULT に相当するエラー) が発生していたので、デバッグを続けました。したがって、プールの背後にある目的の一部を無効にするため、通常は使用しないコードを使用します。
Map.Entity tmp = Map.Entity.EntityPool.chunks[0];
tmp.SetPosition(m, 1, 9);
その後、ブレークポイントを追加してチャンク配列を見ると、チャンク配列のすべての要素の位置は (1, 9) ですが、インデックス 0 を除いてすべて (0, 0) である必要があります。
ここで何が欠けていますか?