Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

.net - A real-world use case for BufferManager

Trying to get to the bottom of an OutOfMemoryException I found that .net's BufferManagers, used by WCF's buffered TransferMode, were responsible for wasting literally hundreds of megabytes (see the question and my own answer on How can I prevent BufferManager / PooledBufferManager in my WCF client app from wasting memory? for details and how I could fix it by simply switching from 'buffered' to 'streamed').

Leaving aside WCF, BufferManagers were invented as a better performing alternative to what you would normally do: simply allocating byte arrays when you need them and relying on the GC to clean them up and recycle once the reference goes out of scope.

So my question is: Has anyone used BufferManagers in a real-world app so that it made a noticeable difference in terms of performance to justify the inconvenience of having to manually .Clear() the BufferManager (if that was necessary)?

And if so, could just manually creating a single byte buffer and keeping a reference to it not have solved that particular problem?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I recently worked on a Proxy service which accepted multiple client connections (upto 500 simultaneous connections). The Proxy relayed client requests to the destination server and relayed back responses from destination servers to the clients. The proxy service used Byte arrays (Byte[]) as buffers to send and receive data. I had no Buffer Manager in place.

The proxy was creating a new byte array every time to send and receive data from socket. The private bytes in the resource monitor kept increasing. Running ANT Memory Profiler tool showed large fragments which kept increasing.

The solution was to implement a simple Buffermanager class to manage the memory used by the Buffers. Here is the code snippet

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);
            }
        }


    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...