一个真实世界的使用案例BufferManager案例、真实、世界、BufferManager

2023-09-04 00:20:14 作者:人比黄花瘦

好一会一个OutOfMemoryException的底部,我发现.NET的 BufferManagers 中,使用WCF的缓冲TransferMode,负责浪费了成百上千兆字节(见的问题,我自己上的如何prevent BufferManager / PooledBufferManager在浪费内存?的详细信息,以及如何我可以通过简单地从'缓冲'到'流')交换解决这个问题我的WCF客户端应用程序。

撇开WCF,BufferManagers的发明为性能更好的替代方案是什么,你通常会做:只是分配字节数组,当你需要他们,依靠GC清理起来,并回收一次参考超出范围

我的问题是:有没有人使用BufferManagers在真实世界中的应用程序以便其作出在性能方面有明显差异的理由不必手动.Clear()的BufferManager(如果必要)的不便?

如果是的话,可以只手动创建一个字节的缓冲区,并保持对它的引用没有解决特定的问题?

解决方案

我最近曾在其接受的多个客户端连接(高达500个并发连接)代理服务。代理中继客户机请求到目标服务器和中继回程从目标服务器至客户端的响应。代理服务使用字节阵列(字节[])作为缓冲剂来发送和接收数据。我没有缓冲区管理器的地方。

代理是每一个从套接字发送和接收数据的时间来创建一个新的字节数组。在资源监视器中的专用字节不断增加。运行ant内存Profiler工具显示出其不断增加的大片段。

解决的办法是实现一个简单的Buffermanager类来管理使用的缓冲内存。这里是code段

 公共类BufferManager
    {
        私人只读INT m_ByteSize;

        私人只读堆叠式和LT; byte []的> m_Buffers;
        私人只读对象m_LockObject =新的对象();

        #区域构造

        公共BufferManager(INT _byteSize,INT _poolCount)
        {
            锁定(m_LockObject)
            {
                m_ByteSize = _byteSize;
                m_Buffers =新的堆栈<字节[]>(_ poolCount);
                的for(int i = 0; I< _poolCount;我++)
                {
                    CreateNewSegment();
                }
            }
        }

        #endregion //构造

        公众诠释AvailableBuffers
        {
            {返回m_Buffers.Count; }
        }


        公共System.Int64 TotalBufferSizeInBytes
        {
            {返回m_Buffers.Count * m_ByteSize; }
        }

        公共System.Int64 TotalBufferSizeInKBs
        {
            {返回(m_Buffers.Count * m_ByteSize / 1000); }
        }

        公共System.Int64 TotalBufferSizeInMBs
        {
            {返回(m_Buffers.Count * m_ByteSize / 1000000); }
        }



        私人无效CreateNewSegment()
        {
            字节[]字节=新字节[m_ByteSize]
            m_Buffers.Push(字节);
        }



        ///<总结>
        ///检查出缓冲器从经理
        ///< /总结>
        公共字节[]退房()
        {
            锁定(m_LockObject)
            {
                如果(m_Buffers.Count == 0)
                {
                    CreateNewSegment();

                }
                返回m_Buffers.Pop();
            }
        }


        ///<总结>
        ///返回一个缓冲区管理器的控制
        ///< /总结>
        ///<说明>
        ///它是客户的责任由缓冲器返回到食槽
        ///在缓冲区调用签入
        ///< /说明>
        公共无效的检入(字节[] _buffer)
        {
            锁定(m_LockObject)
            {
                m_Buffers.Push(_buffer);
            }
        }


    }
 

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?

解决方案

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


    }