Реальный пример использования BufferManager

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

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

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

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

1 ответ

Недавно я работал над прокси-сервисом, который принимал несколько клиентских подключений (до 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);
            }
        }


    }
Другие вопросы по тегам