RecyclableMemoryStream vs MemoryStream
Hi! In this story, I want to share with you my experience working with Streams.
When we are working with Streams, we can have heavy load processes where we add a lot of pressure to the GC
. So, as you know, more pressure on the GC
means less performance because your app will spend more time garbage collecting than executing code.
In order to help us with the performance working with Streams, Microsoft
created this excellent library: RecyclableMemoryStream.
A library to provide pooling for .NET
MemoryStream
objects to improve application performance, especially in the area of garbage collection.
When we are working with large Streams, the library improves the performance by allocating the objects into the gen 2 heap
, this should make that the garbage collection occurs less frequently.
I don’t want to spend time explaining how it works or how to use it because is not need it, they already did a great work with that in the “readme” file. Instead of that, I want to share with you some benchmarks where we can see the difference between using it and not.
The scenario
I want to make this really simple, so imagine that we want to serialize and Zip a big object, in my case, I’ll have a big collection.
To generate a big collection, I made use of Bogus. In the library documentation, they have a section named “The Great C# Example” where they demonstrate the supported features, I took that example to generate a collection of random users. That collection it will be used to perform the benchmarks.
So, let’s see how we can implement it.
Pretty straightforward, first we create a MemoryStream
and a GZipStream
. Then we serialize the collection of users into the zip stream and flush it.
Now, let’s take a look at the implementation making use of the RecyclabeMemoryStreamManager
.
It is very similar to the previous one, except that instead of using a MemoryStream
we are making use of the RecyclabeMemoryStreamManager
.
Show me the code
In order to measure the code performance, I created the following class.
The user’s collection contains 5000 elements, and it will have the same data for both methods since I’m using the same seed to generate them.
Note: I’m creating an instance of the RecyclabeMemoryStreamManager
in the global setup but could be moved to the method, it won’t impact the results.
Taking a look at the results we can see a huge difference between one implementation and the other one. RecyclableMemoryStreamManager
takes a huge advantage in being able to use pool buffers.
You can check the source code from here.
Enjoy and happy coding! : )