Реальный пример использования BufferManager - PullRequest
5 голосов
/ 01 сентября 2011

Пытаясь добраться до сути OutOfMemoryException, я обнаружил, что BufferManager .net, используемый буферизованным TransferMode в WCF, был ответственен за потерю буквально сотен мегабайт (см. Вопрос и мой собственный ответ на Как я могу предотвратить потерю памяти в BufferManager / PooledBufferManager в моем клиентском приложении WCF? для подробностей и как я могу это исправить, просто переключившись с «буферизованного» на «потоковый»).

Оставляя в стороне WCFBufferManager были изобретены как более эффективная альтернатива тому, что вы обычно делаете: просто выделяя байтовые массивы, когда они вам нужны, и полагаясь на GC, чтобы очистить их и утилизировать, когда ссылка выходит из области видимости.

Итаку меня вопрос: кто-нибудь использовал BufferManager в реальном приложении, чтобы оно заметно улучшало производительность, чтобы оправдать неудобство необходимости вручную .Clear () BufferManager (если это было необходимо)?

А если так, то можно просто вручную создатьпоиск единственного байтового буфера и сохранение ссылки на него не решили эту конкретную проблему?

1 Ответ

2 голосов
/ 25 октября 2012

Я недавно работал над прокси-службой, которая принимала несколько клиентских подключений (до 500 одновременных подключений). Прокси-сервер ретранслировал клиентские запросы на сервер назначения и ретранслировал обратные ответы от серверов назначения клиентам. Прокси-сервис использовал байтовые массивы (Byte []) в качестве буферов для отправки и получения данных. У меня не было менеджера буфера на месте.

Прокси каждый раз создавал новый байтовый массив для отправки и получения данных из сокета. Частные байты в мониторе ресурсов продолжали увеличиваться. Запущенный инструмент 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);
            }
        }


    }
...