For the memory release problem, you could offer a manual TrimExcess()
or a Trim(int segmentCount) method. What do you think ?

Sébastien

On 8/9/06, Sébastien Lorion <[EMAIL PROTECTED]> wrote:
I really like your solution! Making this class a singleton as Yun Jin
did seems not like a good choice because different scenarios will most
probably require different parameters.

Maybe a stupid idea, but I think using a stack would provide better
cache locality since it will reuse the last buffer released. Also, the
stack Push/Pop methods are faster (about 3 times on my machine).

Really just a matter of taste, but personally I would use
Request/Release instead of CheckIn/CheckOut. And to be clearer,
AvailableBuffers property should be named AvailableBufferCount.

Thanks for your code!

Sébastien

On 8/9/06, gregory young <[EMAIL PROTECTED]> wrote:
> After some research this seems like a much better method. Here is the
> BufferManager class ... you can use the new overloads for send/receive
> that take ArraySegments in conjunction with it.
>
> Yun Jin gives a great explanation of the problem I am trying to
> resolve here https://blogs.msdn.com/yunjin/archive/2004/01/27/63642.aspx
>
> I think this is better than the solution presented there for a few reasons.
>
> 1) the object will be in the LOH (less work for gc as it never deals
> with compacting the LOH)
> 2) buffers can be dynamically sized .. if you need more buffer just
> ask for more array segments (the socket methods take an
> ILIst<ArraySegment>
>
> One area where this suffers is in dealing with memory management (I
> cannot easily release memory) but generally in such systems that is
> not done often anyways.
>
> Love to hear some feedback.
>
> Cheers,
>
> Greg
>
> BufferManager.cs
>     /// <summary>
>     /// A manager to handle buffers for the socket connections
>     /// </summary>
>     /// <remarks>
>     /// When used in an async call a buffer is pinned. Large numbers
> of pinned buffers
>     /// cause problem with the GC (in particular it causes heap 
fragmentation).
>     ///
>     /// This class maintains a set of large segments and gives clients
> pieces of these
>     /// segments that they can use for their buffers. The alternative
> to this would be to
>     /// create many small arrays which it then maintained. This
> methodology should be slightly
>     /// better than the many small array methodology because in
> creating only a few very
>     /// large objects it will force these objects to be placed on the
> LOH. Since the
>     /// objects are on the LOH they are at this time not subject to
> compacting which would
>     /// require an update of all GC roots as would be the case with
> lots of smaller arrays
>     /// that were in the normal heap.
>     /// </remarks>
>     public class BufferManager {
>         private readonly int m_SegmentChunks;
>         private readonly int m_ChunkSize;
>         private readonly int m_SegmentSize;
>         private readonly Queue<ArraySegment<byte>> m_Buffers;
>         private readonly object m_LockObject = new Object();
>         private readonly List<byte[]> m_Segments;
>
>         /// <summary>
>         /// The current number of buffers available
>         /// </summary>
>         public int AvailableBuffers {
>             get { return m_Buffers.Count; } //do we really care about
> volatility here?
>         }
>
>         /// <summary>
>         /// The total size of all buffers
>         /// </summary>
>         public int TotalBufferSize {
>             get { return m_Segments.Count * m_SegmentSize; } //do we
> really care about volatility here?
>         }
>
>         /// <summary>
>         /// Creates a new segment, makes buffers available
>         /// </summary>
>         private void CreateNewSegment() {
>             byte[] bytes = new byte[m_SegmentChunks * m_ChunkSize];
>             m_Segments.Add(bytes);
>             for (int i = 0; i < m_SegmentChunks; i++) {
>                 ArraySegment<byte> chunk = new
> ArraySegment<byte>(bytes, i * m_ChunkSize, m_ChunkSize);
>                 m_Buffers.Enqueue(chunk);
>             }
>         }
>
>         /// <summary>
>         /// Checks out a buffer from the manager
>         /// </summary>
>         /// <remarks>
>         /// It is the client's responsibility to return the buffer to
> the manger by
>         /// calling <see cref="Checkin"></see> on the buffer
>         /// </remarks>
>         /// <returns>A <see cref="ArraySegment"></see> that can be
> used as a buffer</returns>
>         public ArraySegment<byte> CheckOut() {
>             lock (m_LockObject) {
>                 if (m_Buffers.Count == 0) {
>                     CreateNewSegment();
>                 }
>                 return m_Buffers.Dequeue();
>             }
>         }
>
>         /// <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 <see cref="Checkin"></see> on the buffer
>         /// </remarks>
>         /// <param name="_Buffer">The <see cref="ArraySegment"></see>
> to return to the buffer</param>
>         public void CheckIn(ArraySegment<byte> _Buffer) {
>             lock (m_LockObject) {
>                 m_Buffers.Enqueue(_Buffer);
>             }
>         }
>
>         #region constructors
>
>         /// <summary>
>         /// Constructs a new <see cref="BufferManager"></see> object
>         /// </summary>
>         /// <param name="_SegmentChunks">The number of chunks to
> create per segment</param>
>         /// <param name="_ChunkSize">The size of a chunk in bytes</param>
>         public BufferManager(int _SegmentChunks, int _ChunkSize) :
> this(_SegmentChunks, _ChunkSize, 1) { }
>
>         /// <summary>
>         /// Constructs a new <see cref="BufferManager"></see> object
>         /// </summary>
>         /// <param name="_SegmentChunks">The number of chunks to
> create per segment</param>
>         /// <param name="_ChunkSize">The size of a chunk in bytes</param>
>         /// <param name="_InitialSegments">The initial number of
> segments to create</param>
>         public BufferManager(int _SegmentChunks, int _ChunkSize, int
> _InitialSegments) {
>             m_SegmentChunks = _SegmentChunks;
>             m_ChunkSize = _ChunkSize;
>             m_SegmentSize = m_SegmentChunks * m_ChunkSize;
>             m_Buffers = new Queue<ArraySegment<byte>>(_SegmentChunks *
> _InitialSegments);
>             m_Segments = new List<byte[]>();
>             for (int i = 0; i < _InitialSegments; i++) {
>                 CreateNewSegment();
>             }
>         }
>         #endregion
>     }
>
> On 8/1/06, gregory young <[EMAIL PROTECTED]> wrote:
> > Ok so I think everyone can agree that creating buffers on the fly in
> > an async socket server is bad ... there is alot of literature
> > available on the problems this will cause with the heap. I am looking
> > at a few options to get around this.
> >
> > 1) Have a BufferPool class that hands out ArraySegment<byte> portions
> > of a larger array (large enough that it would be in the LOH). If all
> > of the array is used create another big segment.
> >
> > 2) Create a bunch of smaller arrays for use by the bufferpool class
> > and have it hand them back
> >
> > In both 1 & 2 I would probably have the connection use their buffer
> > for the duration of the connection. I would internally hold a list of
> > the free blocks. When a connection was done ith its buffer it would
> > have to release it back to this pool. My thought is that #2 might be
> > better for dealing with cases where I want to shrink the number of
> > buffers allocated from the previous maximum if needed.
> >
> > In general I lean towards #1 ... but figured I would check if I might
> > be missing something.
> >
> > Thanks in advance,
> >
> > Greg Young
> >
>
>
> --
> If knowledge can create problems, it is not through ignorance that we
> can solve them.
>
> Isaac Asimov
>
> ===================================
> This list is hosted by DevelopMentor(r)  http://www.develop.com
>
> View archives and manage your subscription(s) at http://discuss.develop.com
>


--
Sébastien Lorion
Software Architect / Architecte organique
[EMAIL PROTECTED]



--
Sébastien Lorion
Software Architect / Architecte organique
[EMAIL PROTECTED]

===================================
This list is hosted by DevelopMentor®  http://www.develop.com

View archives and manage your subscription(s) at http://discuss.develop.com

Reply via email to