Reputation: 2920
Is it possible to re-use memory that was used in a string to byte array conversion?
The application has to send large strings over network with 60fps. This seems to put way too much pressure on the GC. So is it possible to re-use the byte arrays created by the string conversion somehow?
These are my current serialization methods:
public static byte[] SerializeJson(DrawDescriptionLayer layer)
{
var s = JsonConvert.SerializeObject(layer, js);
return Encoding.UTF8.GetBytes(s); //rent from array pool here
}
Or using streams:
public static byte[] SerializeJson2(DrawDescriptionLayer layer)
{
using (var ms = new MemoryStream())
using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
using (JsonTextWriter jsonWriter = new JsonTextWriter(writer))
{
JsonSerializer ser = JsonSerializer.Create(js);
ser.Serialize(jsonWriter, layer);
jsonWriter.Flush();
return ms.ToArray(); //rent from array pool here
}
}
I am aware that i should write a custom binary serializer, but Newtonsoft.Json worked out of the box and the app uses third party types that have no serialization attributes.
Upvotes: 2
Views: 1694
Reputation: 21
As far as streams, Microsoft.IO.RecyclableMemoryStream was specifically created to reduce the cost of garbage collections incurred by frequent large allocations. You could modify your stream example like:
private static readonly RecyclableMemoryStreamManager _manager = new RecyclableMemoryStreamManager();
public static byte[] SerializeJson2(DrawDescriptionLayer layer)
{
using (var ms = _manager.GetStream())
using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8))
using (JsonTextWriter jsonWriter = new JsonTextWriter(writer))
{
JsonSerializer ser = JsonSerializer.Create(js);
ser.Serialize(jsonWriter, layer);
jsonWriter.Flush();
return ms.ToArray();
}
}
The use of ToArray(), however, copies into a new array that is never pooled, which according to the docs "... wipes out many of the benefits of RecyclableMemoryStream completely.". So look into using GetBuffer() instead.
Upvotes: 2
Reputation: 1480
If performance and memory allocation are major concerns, you should strongly consider using utf8json.
Instead of using both the slow JsonConvert.SerializeObject
method, followed by the allocation-heavy UTF8.GetBytes
, utf8json can do this in one pass:
public byte[] SerializeJson(DrawDescriptionLayer layer)
{
return Utf8Json.JsonSerializer.Serialize(layer, Utf8Json.Resolvers.StandardResolver.Default);
}
The library is optimized towards performance and low allocation, and it's used in software like ElasticSearch's recommended .NET client.
Also make sure that the DrawDescriptionLayer
is a DTO that is highly optimized for cheap JSON serialization and doesn't contain anything not used in the network transfer.
Good luck!
Upvotes: 1