6

OutOfMemoryException の一番下に到達しようとすると、WCF のバッファリングされた TransferMode で使用される .net のBufferManagersが、文字通り数百メガバイトを浪費する責任があることがわかりました ( WCF クライアントで BufferManager / PooledBufferManager を防ぐ方法に関する質問と自分の回答を参照してください)アプリはメモリを浪費していませんか?詳細と、単に「バッファリング」から「ストリーミング」に切り替えるだけでそれを修正する方法について)。

WCF はさておき、BufferManagers は、必要なときにバイト配列を割り当て、GC に依存してそれらをクリーンアップし、参照が範囲外になったらリサイクルするという、通常行うよりも優れたパフォーマンスの代替手段として発明されました。

私の質問は次のとおりです:実際のアプリで BufferManagers を使用して、手動で .Clear() BufferManager (必要な場合) を実行する不便さを正当化するために、パフォーマンスの面で顕著な違いを生み出した人はいますか?

もしそうなら、1 バイトのバッファを手動で作成し、それへの参照を保持するだけでは、その特定の問題は解決されないのでしょうか?

4

1 に答える 1

3

私は最近、複数のクライアント接続 (最大 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);
            }
        }


    }
于 2012-10-25T13:51:46.910 に答える