2011-09-01 9 views
5

Intentando llegar al final de una OutOfMemoryException encontré que el .net BufferManagers, utilizado por el modo de transferencia buffer de WCF, fue responsable de perder literalmente cientos de megabytes (vea la pregunta y mi propia respuesta en How can I prevent BufferManager/PooledBufferManager in my WCF client app from wasting memory? para más detalles y cómo podría solucionarlo simplemente cambiando de 'almacenado' a 'transmitido').Un caso de uso real para BufferManager

Dejando a un lado WCF, BufferManagers se inventó como una alternativa de mejor rendimiento de lo que normalmente haría: simplemente asignar matrices de bytes cuando los necesita y confiar en el GC para limpiarlos y reciclar una vez que la referencia se sale del alcance.

Así que mi pregunta es: ¿Alguien ha utilizado BufferManagers en una aplicación del mundo real para que haya una diferencia notable en términos de rendimiento para justificar la inconveniencia de tener que manualmente. Borrar() el BufferManager (si fuera necesario) ?

Y, en caso afirmativo, ¿podría haber creado un búfer de byte solo manualmente y mantener una referencia no ha resuelto ese problema en particular?

Respuesta

2

Recientemente trabajé en un servicio proxy que aceptaba varias conexiones de cliente (hasta 500 conexiones simultáneas). El Proxy transmitió las solicitudes del cliente al servidor de destino y transmitió las respuestas de los servidores de destino a los clientes. El servicio de proxy usa matrices de bytes (Byte []) como búferes para enviar y recibir datos. No tenía un administrador de búfer en su lugar.

El proxy creaba una nueva matriz de bytes cada vez para enviar y recibir datos del socket. Los bytes privados en el monitor de recursos siguieron aumentando. La herramienta ANT Memory Profiler ejecutaba fragmentos grandes que seguían aumentando.

La solución fue implementar una clase simple Buffermanager para administrar la memoria utilizada por los Buffers. Aquí está el fragmento de código

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

he editado mi pregunta para que sea (incluso) más claro que estoy hablando de [.NET de] (http://msdn.microsoft.com/en-us/library/ system.servicemodel.channels.buffermanager (v = vs.100) .aspx). No estoy seguro de por qué escribiste el tuyo (y lo usaste para responder mi pregunta sobre la implementación de .net). Pero de todos modos, aparte del hecho de que su implementación nunca se libera una vez que adquirió la memoria, ¿describió cómo le va en contra de dejar el trabajo al GC integrado? –

+0

El segundo párrafo contiene resultados de perfilador. –

Cuestiones relacionadas