Which JSON Library Creates the Most Garbage?
Which JSON library creates the most garbage? That’s a common question I get in response to my JSON articles. Today’s article finds out the answer!
As with last week’s article, today’s contenders are:
- Unity3D 5.4.0f3
- LitJSON 0.9.0
- Json.NET 9.0.1
- Full Serializer 1.1.0
They’ll all be serializing and deserializing these types:
[Serializable] public class SaveGame { public string Name; public int HighScore; public List<InventoryItem> Inventory; } [Serializable] public class InventoryItem { public int Id; public int Quantity; }
And today we’ll run them all in the Unity editor’s profiler in “deep” mode using the following script:
using System; using System.Collections.Generic; using System.Text; using UnityEngine; using LitJson; using Newtonsoft.Json; using FullSerializer; [Serializable] public class SaveGame { public string Name; public int HighScore; public List<InventoryItem> Inventory; } [Serializable] public class InventoryItem { public int Id; public int Quantity; } class TestScript : MonoBehaviour { void Start() { var saveGame = new SaveGame { Name = "Speed Run", HighScore = 10000, Inventory = new List<InventoryItem> { new InventoryItem { Id = 100, Quantity = 5 }, new InventoryItem { Id = 200, Quantity = 20 } } }; // Warm up reflection JsonUtility.ToJson(saveGame); JsonMapper.ToJson(saveGame); JsonConvert.SerializeObject(saveGame); var fsSerializer = new fsSerializer(); fsData fsData; fsSerializer.TrySerialize(saveGame, out fsData); fsJsonPrinter.CompressedJson(fsData); var tempSaveGame = new SaveGame(); TestGarbage(saveGame, tempSaveGame, fsSerializer); } void TestGarbage(SaveGame saveGame, SaveGame tempSaveGame, fsSerializer fsSerializer) { var json = TestUnitySerialize(saveGame); TestUnityDeserialize(json); json = TestLitJsonSerialize(saveGame); TestLitJsonDeserialize(json); json = TestJsonDotNetSerialize(saveGame); TestJsonDotNetDeserialize(json); json = TestFullSerializerSerialize(saveGame, fsSerializer); TestFullSerializerDeserialize(json, fsSerializer, tempSaveGame); } string TestUnitySerialize(SaveGame saveGame) { return JsonUtility.ToJson(saveGame); } SaveGame TestUnityDeserialize(string json) { return JsonUtility.FromJson<SaveGame>(json); } string TestLitJsonSerialize(SaveGame saveGame) { return JsonMapper.ToJson(saveGame); } SaveGame TestLitJsonDeserialize(string json) { return JsonMapper.ToObject<SaveGame>(json); } string TestJsonDotNetSerialize(SaveGame saveGame) { return JsonConvert.SerializeObject(saveGame); } SaveGame TestJsonDotNetDeserialize(string json) { return JsonConvert.DeserializeObject<SaveGame>(json); } string TestFullSerializerSerialize(SaveGame saveGame, fsSerializer serializer) { fsData fsData; serializer.TrySerialize(saveGame, out fsData); return fsJsonPrinter.CompressedJson(fsData); } SaveGame TestFullSerializerDeserialize(string json, fsSerializer serializer, SaveGame saveGame) { var fsData = fsJsonParser.Parse(json); serializer.TryDeserialize<SaveGame>(fsData, ref saveGame); return saveGame; } }
If you want to try out the test yourself, simply paste the above code into a TestScript.cs
file in your Unity project’s Assets
directory and attach it to the main camera game object in a new, empty project.
I did this and got the following results. The important column here is labeled “GC Alloc”:
Here’s the same data in table form with KB columns approximated in bytes.
Library | Serialization Garbage | Deserialization Garbage |
---|---|---|
Unity | 260 | 244 |
LitJSON | 819.2 | 15155.2 |
Json.NET | 1843.2 | 11161.6 |
FullSerializer | 4505.6 | 34816 |
And here’s that table graphed:
It’s clear that Unity’s JSONUtility
class produces far less garbage than any other JSON library. It’s 4x less than second place LitJSON at serialization and 17x less than last place FullSerializer. Likewise for deserialization, it’s 45x less than second place Json.NET and a whopping 142x less than last place FullSerializer.
That establishes a clear order when it comes to garbage: Unity is best and FullSerializer is worst. LitJSON and Json.NET are in the middle with Json.NET having a little less total garbage creation.
So just as with serialization and deserialization speed, Unity’s JsonUtility
wins again on the garbage creation front. Even in a more detailed breakdown using Unity 5.3, JsonUtility
was the clear performance winner. So from that perspective it’s a natural choice.
Would you always choose JsonUtility
or do you have another preferred JSON library? What keeps you from using JsonUtility
? Let me know in the comments!
#1 by Ed Earl on September 27th, 2016 ·
Thanks for putting this together! Very informative!
There are several things which JsonUtility won’t serialize – for example (IIRC) Dictionaries, or class members declared as a base class type to which an object of a derived type is assigned. ISerializationCallbackReceiver.OnBeforeSerialize can be implemented to mitigate this somewhat. No doubt other JSON libraries have their own limitations, too.
Another mildly annoying thing is that enum values are serialized as the equivalent int value.
Unity people have responded to forum posts to say they’re aware of these issues, however, so maybe some improvements will be forthcoming, making it even harder to argue against JsonUtility.
#2 by Simon on November 7th, 2016 ·
​Is Unitys JsonUtility capable of serializing properties, is there a way to override the process rules and add own serialization logic? The interface seems to only allow very limited usage scenarios
#3 by jackson on November 7th, 2016 ·
It’s definitely limited compared to some of the other JSON libraries. That includes not being able to serialize properties. Only fields are serialized, but you can work around this by using a backing field annotated with the
[SerializeField]
attribute:Output: