2011-09-01 9 views
5

OutOfMemoryExceptionの底部に到達しようとしました.netのBufferManagersは、WCFのバッファされたTransferModeで使用され、文字通り何百メガバイトも無駄にしていました。詳細についてはHow can I prevent BufferManager/PooledBufferManager in my WCF client app from wasting memory?を参照してください。単に「バッファされた」から「ストリーミングされた」に切り替えるだけで問題を解決できます)。BufferManagerの現実的な使用例

BufferManagersは、通常必要とするときにバイト配列を割り当てるだけでなく、参照が範囲外になったらそれらをクリーンアップおよびリサイクルするためにGCに頼って、通常どおりに行うより優れた代替手段として発明されました。

だから私の質問です:実際のアプリケーションでBufferManagersを使用していた人は、バッファーマネージャーを手作業でClear()しなければならないという不都合を正当化するために、 ?

もしそうなら、手動で1バイトのバッファを作成し、そのバッファへの参照を保持してその特定の問題を解決できなかったでしょうか?

答えて

2

私は最近、複数のクライアント接続(最大500の同時接続)を受け入れたプロキシサービスを開発しました。プロキシは、クライアント要求を宛先サーバーに中継し、応答を宛先サーバーからクライアントに中継しました。プロキシサービスは、バイト配列(Byte [])をバッファとして使用してデータを送受信しました。 Buffer Managerはありませんでした。

プロキシがソケットからデータを送受信するたびに、新しいバイト配列を作成していました。リソースモニターのプライベートバイトは増加し続けました。 ANT Memory Profilerツールを実行すると、大きな断片が増え続けました。

解決策は、Buffersによって使用されるメモリを管理するための単純なBuffermanagerクラスを実装することでした。ここにコードスニペットがあります

public class BufferManager 
    { 
     private readonly int m_ByteSize; 

     private readonly Stack<byte[]> m_Buffers; 
     private readonly object m_LockObject = new Object(); 

     #region constructors 

     public BufferManager(int _byteSize, int _poolCount) 
     { 
      lock (m_LockObject) 
      { 
       m_ByteSize = _byteSize; 
       m_Buffers = new Stack<Byte[]>(_poolCount); 
       for (int i = 0; i < _poolCount; i++) 
       { 
        CreateNewSegment(); 
       } 
      } 
     } 

     #endregion //constructors 

     public int AvailableBuffers 
     { 
      get { return m_Buffers.Count; } 
     } 


     public System.Int64 TotalBufferSizeInBytes 
     { 
      get { return m_Buffers.Count * m_ByteSize; } 
     } 

     public System.Int64 TotalBufferSizeInKBs 
     { 
      get { return (m_Buffers.Count * m_ByteSize/1000); } 
     } 

     public System.Int64 TotalBufferSizeInMBs 
     { 
      get { return (m_Buffers.Count * m_ByteSize/1000000); } 
     } 



     private void CreateNewSegment() 
     { 
      byte[] bytes = new byte[m_ByteSize]; 
      m_Buffers.Push(bytes); 
     } 



     /// <summary> 
     /// Checks out a buffer from the manager 
     /// </summary>   
     public Byte[] CheckOut() 
     { 
      lock (m_LockObject) 
      { 
       if (m_Buffers.Count == 0) 
       { 
        CreateNewSegment(); 

       } 
       return m_Buffers.Pop(); 
      } 
     } 


     /// <summary> 
     /// Returns a buffer to the control of the manager 
     /// </summary> 
     ///<remarks> 
     /// It is the client’s responsibility to return the buffer to the manger by 
     /// calling Checkin on the buffer 
     ///</remarks> 
     public void CheckIn(Byte[] _Buffer) 
     { 
      lock (m_LockObject) 
      { 
       m_Buffers.Push(_Buffer); 
      } 
     } 


    } 
+0

私は[私の話]([もみ)](http://msdn.microsoft.com/en-us/library/)についてさらに明確にするために私の質問を編集しました。 system.servicemodel.channels.buffermanager(v = vs.100).aspx)。私はあなたが自分自身を書いた理由をよく分かりません(そして、.netの実装について私の質問に答えるためにそれを使いました)。しかし、とにかく、あなたの実装が一度獲得したメモリを解放しないという事実を別にすれば、組み込みGCに仕事を任せているのはどのようなことでしょうか? –

+0

2番目の段落には、プロファイラ結果が含まれています。 –

関連する問題