2011-09-01 5 views
5

OutOfMemoryException의 맨 아래로 이동하려고 함. WCF의 버퍼 된 TransferMode에서 사용되는 .net의 BufferManagers이 말 그대로 수백 메가 바이트를 낭비하는 것을 발견했습니다. How can I prevent BufferManager/PooledBufferManager in my WCF client app from wasting memory? 자세한 내용은 어떻게 간단히 '버퍼링'에서 '스트리밍'으로 전환하여 해결할 수 있습니까?)BufferManager의 실제 사용 사례

WCF를 제외하고 BufferManagers는 평상시와 같이 바이트 배열을 할당하고 GC를 사용하여 참조가 범위를 벗어나면이를 정리하고 재활용하는 대신에 단순히 바이트 배열을 할당하는 대신에 더 나은 성능의 대안으로 개발되었습니다.

내 질문은 : 현실적인 응용 프로그램에서 BufferManagers를 사용하여 BufferManager를 수동으로 .Clear()해야하는 불편 함을 정당화하기 위해 성능 측면에서 눈에 띄는 차이를 만들었습니까? (필요한 경우) ?

그렇다면 수동으로 단일 바이트 버퍼를 만들고 해당 버퍼에 대한 참조를 유지하지 않아도 특정 문제가 해결 될 수 있습니까?

답변

2

최근 여러 개의 클라이언트 연결 (최대 500 개의 동시 연결)을 허용하는 프록시 서비스에서 작업했습니다. 프록시는 클라이언트 요청을 대상 서버로 중계하고 대상 서버에서 클라이언트로 응답을 다시 전달했습니다. 프록시 서비스는 Byte 배열 (Byte [])을 버퍼로 사용하여 데이터를 보내고받습니다. Buffer Manager가 없었습니다.

프록시가 소켓에서 데이터를 보내고받을 때마다 새 바이트 배열을 생성하고있었습니다. 자원 모니터의 개인용 바이트는 계속 증가했습니다. ANT Memory Profiler 도구를 실행하면 커다란 조각이 계속 증가했습니다.

이 솔루션은 간단한 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

저는 [.net] (http://msdn.microsoft.com/en-us/library/)에 대해 더 명확하게 설명하기 위해 제 질문을 편집했습니다. system.servicemodel.channels.buffermanager (v = vs.100) .aspx). 나는 왜 당신이 자신의 것을 썼는지 (그리고 그것을 .net의 구현에 대한 나의 질문에 대답하기 위해) 사용했는지 확신 할 수 없다. 하지만 어쨌든, 당신의 구현은 결코 한번 획득 된 메모리를 해제하지 않는다는 사실을 제외하고, 내장 된 GC에 작업을 남겨 두는 것에 대해 어떻게 평가 하는가? –

+0

두 번째 단락은 프로파일 러 결과를 포함합니다. –