2011-09-01 14 views
5

Cercando di andare in fondo a un OutOfMemoryException ho scoperto che .net's BufferManagers, utilizzato dal buffer Buffed TransferMode, era responsabile di sprecare letteralmente centinaia di megabyte (vedere la domanda e la mia risposta su How can I prevent BufferManager/PooledBufferManager in my WCF client app from wasting memory? per i dettagli e come ho potuto risolverlo passando semplicemente da 'buffer' a 'streamed').Un caso di utilizzo del mondo reale per BufferManager

Tralasciando WCF, BufferManagers stati inventati come più performante alternativa a quanto si farebbe normalmente: semplicemente assegnando matrici di byte quando necessario e basandosi sulla GC per pulirli e riciclare una volta il riferimento passa nell'ambito.

Quindi la mia domanda è: qualcuno ha usato BufferManager in un'app reale in modo che abbia fatto una differenza notevole in termini di prestazioni per giustificare l'inconveniente di dover manualmente .Clear() il BufferManager (se fosse necessario) ?

E se così fosse, potrebbe semplicemente creare manualmente un buffer a byte singolo e mantenere un riferimento ad esso non ha risolto quel particolare problema?

risposta

2

Recentemente ho lavorato a un servizio Proxy che accetta più connessioni client (fino a 500 connessioni simultanee). Il proxy inoltrava le richieste del client al server di destinazione e inoltrava le risposte dai server di destinazione ai client. Il servizio proxy utilizzava gli array Byte (Byte []) come buffer per inviare e ricevere dati. Non avevo nessun Buffer Manager sul posto.

Il proxy stava creando un nuovo array di byte ogni volta per inviare e ricevere dati dal socket. I byte privati ​​nel monitor delle risorse continuavano ad aumentare. L'esecuzione dello strumento ANT Memory Profiler mostrava grossi frammenti che continuavano ad aumentare.

La soluzione era implementare una semplice classe Buffermanager per gestire la memoria utilizzata dai buffer. Ecco il frammento di codice

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

ho modificato la mia domanda per renderlo (anche) più chiaro che sto parlando di [.NET] (http://msdn.microsoft.com/en-us/library/ system.servicemodel.channels.buffermanager (v = VS.100) .aspx). Non sono sicuro del motivo per cui hai scritto il tuo (e l'ho usato per rispondere alla mia domanda sull'implementazione di .net). Ma comunque, a parte il fatto che la tua implementazione non viene mai rilasciata una volta acquisita memoria, hai definito come va contro l'abbandono del lavoro nel GC integrato? –

+0

Il secondo paragrafo contiene i risultati del profiler. –

Problemi correlati