Friday, December 30, 2016

Object Pooling and Memory Streams

The theme of this year, which I will talk about in my 2016 retrospective, has been optimization. It's been a fun journey, and I have really enjoyed getting down and dirty with profiling garbage collection, using spin waits, and aggressive inlining.

I want to end this year on a fun note: object pooling.

A great use case for this would be making HTTP requests with serialized objects. When you serialize an object, and then place it in a HttpContent object, you are probable creating several buffers (byte arrays) each time. For example, if you are using Newtonsoft to serialize an object and then adding that to a string content object for your request, then you are probably using more memory than you need. But that is getting ahead of ourselves...

Come back next week for a blog post about efficient JSON Content serialization!

For now, let's focus on building an object pool. Really all that we need is a preallocated array to store unused objects in, and then a super efficient thread safe data structure to pool (get and set) those objects.

How does pooling memory streams help us?

When you create a MemoryStream, it creates a byte array. As that byte array grows, the memory stream resizes it by allocating a new larger array and then copying your bytes into it. This is inefficient not only because it creates new objects and throws the old ones away, but also because it has to do the leg work of copying the content each time it resizes.

How can we reuse memory streams? Just set the length to zero!

Internally this will just set an index and empty the array, but the internal data structures will be preserved for future use. Thus, by putting memory streams into an object pool, we can drastically increase our efficiency.

Here is a demo of using the Tact.NET ObjectPool to pool MemoryStreams...

[Fact]
public void MemoryStreamPoolDemo()
{
    using (var pool = new ObjectPool<MemoryStream>(100, () => new MemoryStream()))
    {
        var memoryStream1 = pool.Acquire();
 
        memoryStream1.SetLength(0);
        Assert.Equal(0, memoryStream1.Capacity);
 
        memoryStream1.Write(new byte[] {1, 0, 1, 0, 1}, 0, 5);
 
        var array1 = memoryStream1.ToArray();
        Assert.Equal(5, array1.Length);
        Assert.Equal(1, array1.First());
        Assert.Equal(1, array1.First());
 
        pool.Release(memoryStream1);
 
        var memoryStream2 = pool.Acquire();
        Assert.Same(memoryStream1, memoryStream2);
 
        memoryStream2.SetLength(0);
        Assert.Equal(256, memoryStream2.Capacity);
 
        memoryStream2.Write(new byte[] { 0, 1, 0 }, 0, 3);
 
        var array2 = memoryStream2.ToArray();
        Assert.Equal(3, array2.Length);
        Assert.Equal(0, array2.First());
        Assert.Equal(0, array2.First());
    }
}

Enjoy,
Tom

3 comments:

  1. Bu web sitesini hızlı bir şekilde ziyaret etmek ve tüm meslektaşların görüşlerini okumak harika.
    Bu yazının konusu hakkında, aynı zamanda aşinalık kazanmaya da hevesliyim.


    https://www.totosafeguide.com

    ReplyDelete
  2. Do you require immediate assistance with your paper help? Look no further because we are here to help you right away. Don't be concerned if you need assistance with a tiny piece or looking for affordable papers. We have a committed team of professionals looking out for your best interests. Our online paper help writers have a wide range of certifications and years of experience working on research papers for tens of thousands of customers around the world. Forget about the restless hours and hectic days spent attempting to assess your study findings. We guarantee that you will receive high-quality essays by the deadline.

    ReplyDelete
  3. Your Site is very nice, and it's very helping us this post is unique and interesting, thank you for sharing this awesome information. and visit our blog site also. Satta King

    ReplyDelete

Real Time Web Analytics