2011-09-01 15 views
5

Próba znalezienia się na dnie wyjątku OutOfMemoryException Stwierdziłem, że. BufferManagers, używany przez buforowany przez WCF TransferMode, był odpowiedzialny za marnowanie dosłownie setek megabajtów (zobacz pytanie i moją własną odpowiedź na How can I prevent BufferManager/PooledBufferManager in my WCF client app from wasting memory?, aby uzyskać szczegółowe informacje i dowiedzieć się, jak to naprawić, przełączając się z "buforowanego" na "przesyłany strumieniowo").Prawdziwy przypadek użycia BufferManager

Pomijanie WCF, BufferManagers zostały wymyślone jako lepsza alternatywa dla tego, co normalnie zrobiłbyś: po prostu przydzielanie tablic bajtowych, gdy ich potrzebujesz i poleganie na GC, aby je wyczyścić i poddać recyklingowi, gdy odniesienie wykracza poza zakres.

Moje pytanie brzmi: czy ktoś użył modułów BufferManagers w rzeczywistej aplikacji, aby uzyskać zauważalną różnicę pod względem wydajności, aby usprawiedliwić niedogodności związane z koniecznością ręcznego czyszczenia .Clear() BufferManager (jeśli było to konieczne) ?

A jeśli tak, czy ręczne utworzenie bufora jednobajtowego i zachowanie odniesienia do niego nie rozwiązałoby tego konkretnego problemu?

Odpowiedz

2

Niedawno pracowałem nad usługą Proxy, która akceptowała wiele połączeń klientów (do 500 równoczesnych połączeń). Serwer proxy przekazał żądania klientów do serwera docelowego i przekazał odpowiedzi z serwerów docelowych do klientów. Usługa proxy używała tablic bajtowych (Byte []) jako buforów do wysyłania i odbierania danych. Nie miałem żadnego menedżera bufora.

Serwer proxy tworzył nową tablicę bajtów za każdym razem, aby wysyłać i odbierać dane z gniazda. Prywatne bajty w monitorze zasobów stale rosły. Uruchomienie narzędzia ANT Memory Profiler pokazało duże fragmenty, które ciągle rosły.

Rozwiązaniem było wdrożenie prostej klasy Buffermanager w celu zarządzania pamięcią używaną przez bufory. Oto fragment kodu

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

edytowany moje pytanie, aby to (jeszcze) bardziej jasne, że mówię o [.net'S] (http://msdn.microsoft.com/en-us/library/ system.servicemodel.channels.buffermanager (v = vs.100) .aspx). Nie wiem, dlaczego napisałeś własną (i użyłeś jej do odpowiedzi na moje pytanie dotyczące implementacji .net). Ale poza tym, niezależnie od tego, że twoja implementacja nigdy nie zwalnia raz zdobytej pamięci, czy profilowałeś, jak radzi sobie z rezygnacją z pracy do wbudowanego GC? –

+0

Drugi akapit zawiera wyniki profilera. –

Powiązane problemy