Unity 5.3 came out this week and introduced a new, built-in JSON serializer library. Today’s article compares its performance against some popular third-party JSON serializer libraries to see if Unity’s version is any faster. Read on for the results!

Today’s contenders are:

They will all be made to serialize this simple “save game” structure:

[Serializable]
public class SaveGame
{
	public string Name;
	public int HighScore;
	public List<InventoryItem> Inventory;
}
 
[Serializable]
public class InventoryItem
{
	public int Id;
	public int Quantity;
}

The test will judge them on three grounds:

  • JSON size
  • Serialization time
  • Deserialization time

There is also the “ease of use” factor. It’s hard to compare, but you can see that they all offer one-liners for both serialization and deserialization. I’ll call this a tie:

using UnityEngine;
var unityJson = JsonUtility.ToJson(saveGame);
var unitySaveGame = JsonUtility.FromJson<SaveGame>(unityJson);
 
using LitJson;
var litJsonJson = JsonMapper.ToJson(saveGame);
var litJsonSaveGame = JsonMapper.ToObject<SaveGame>(litJsonJson);
 
using Newtonsoft.Json;
var jsonDotNetJson = JsonConvert.SerializeObject(saveGame);
var jsonDotNetSaveGame = JsonConvert.DeserializeObject<SaveGame>(jsonDotNetJson);

Now for the size and performance test script:

using System;
using System.Collections.Generic;
using System.Text;
 
using UnityEngine;
 
using LitJson;
using Newtonsoft.Json;
 
[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
{
	string report = "";
 
	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 stopwatch = new System.Diagnostics.Stopwatch();
		const int reps = 10000;
		string unityJson = null;
		string litJsonJson = null;
		string jsonDotNetJson = null;
		SaveGame unitySaveGame = null;
		SaveGame litJsonSaveGame = null;
		SaveGame jsonDotNetSaveGame = null;
 
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			unityJson = JsonUtility.ToJson(saveGame);
		}
		var unitySerializeTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			litJsonJson = JsonMapper.ToJson(saveGame);
		}
		var litJsonSerializeTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			jsonDotNetJson = JsonConvert.SerializeObject(saveGame);
		}
		var jsonDotNetSerializeTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			unitySaveGame = JsonUtility.FromJson<SaveGame>(unityJson);
		}
		var unityDeserializeTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			litJsonSaveGame = JsonMapper.ToObject<SaveGame>(litJsonJson);
		}
		var litJsonDeserializeTime = stopwatch.ElapsedMilliseconds;
 
		stopwatch.Reset();
		stopwatch.Start();
		for (var i = 0; i < reps; ++i)
		{
			jsonDotNetSaveGame = JsonConvert.DeserializeObject<SaveGame>(jsonDotNetJson);
		}
		var jsonDotNetDeserializeTime = stopwatch.ElapsedMilliseconds;
 
		report += "Unity: " + unityJson + "\n";
		report += "LitJSON: " + litJsonJson + "\n";
		report += "Json.NET: " + jsonDotNetJson + "\n";
		PrintSaveGame("Unity", unitySaveGame);
		PrintSaveGame("LitJSON", litJsonSaveGame);
		PrintSaveGame("Json.NET", jsonDotNetSaveGame);
 
		var unitySize = Encoding.UTF8.GetBytes(unityJson).Length;
		var litJsonSize = Encoding.UTF8.GetBytes(litJsonJson).Length;
		var jsonDotNetSize = Encoding.UTF8.GetBytes(jsonDotNetJson).Length;
		report += string.Format(
			"Library,Size,SerializeTime,Deserialize Time\n" +
			"Unity,{0},{1},{2}\n" +
			"LitJSON,{3},{4},{5}\n" +
			"Json.NET,{6},{7},{8}\n",
			unitySize, unitySerializeTime, unityDeserializeTime,
			litJsonSize, litJsonSerializeTime, litJsonDeserializeTime,
			jsonDotNetSize, jsonDotNetSerializeTime, jsonDotNetDeserializeTime
		);
	}
 
	void PrintSaveGame(string title, SaveGame saveGame)
	{
		var builder = new StringBuilder(title);
		builder.Append(":\n\tName=");
		builder.Append(saveGame.Name);
		builder.Append('\n');
		builder.Append("\tHighScore=");
		builder.Append(saveGame.HighScore);
		builder.Append("\n");
		builder.Append("\tInventory=\n");
		foreach (var item in saveGame.Inventory)
		{
			builder.Append("\t\t");
			builder.Append("Id=");
			builder.Append(item.Id);
			builder.Append(", Quantity=");
			builder.Append(item.Quantity);
			builder.Append('\n');
		}
		report += builder.ToString() + "\n";
	}
 
	void OnGUI()
	{
		GUI.TextArea(new Rect(0, 0, Screen.width, Screen.height), report);
	}
}

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. Then build in non-development mode for 64-bit processors and run it windowed at 640×480 with fastest graphics. I ran it that way on this machine:

  • 2.3 Ghz Intel Core i7-3615QM
  • Mac OS X 10.11.2
  • Unity 5.3.0f4, Mac OS X Standalone, x86_64, non-development
  • 640×480, Fastest, Windowed

And here are the results I got:

Library Size SerializeTime Deserialize Time
Unity 101 68 78
LitJSON 101 71 253
Json.NET 101 94 151

JSON Size Graph

JSON Performance Graph

All three JSON serializers produced the exact same, minimal JSON:

Unity: {"Name":"Speed Run","HighScore":10000,"Inventory":[{"Id":100,"Quantity":5},{"Id":200,"Quantity":20}]}
LitJSON: {"Name":"Speed Run","HighScore":10000,"Inventory":[{"Id":100,"Quantity":5},{"Id":200,"Quantity":20}]}
Json.NET: {"Name":"Speed Run","HighScore":10000,"Inventory":[{"Id":100,"Quantity":5},{"Id":200,"Quantity":20}]}

They all deserialized to the exact same SaveGame instance:

Unity:
	Name=Speed Run
	HighScore=10000
	Inventory=
		Id=100, Quantity=5
		Id=200, Quantity=20
 
LitJSON:
	Name=Speed Run
	HighScore=10000
	Inventory=
		Id=100, Quantity=5
		Id=200, Quantity=20
 
Json.NET:
	Name=Speed Run
	HighScore=10000
	Inventory=
		Id=100, Quantity=5
		Id=200, Quantity=20

But when it comes to serialization and deserialization performance, the differences started to show. Unity’s new JsonUtility serialized and deserialized the fastest. It’s serialization time was only slightly faster than second-place LitJSON, but about a third faster than Json.NET.

When it comes to deserialization, Unity’s JsonUtility really outshines the competition. It completed the task in about half the time that it took Json.NET and about a third the time as LitJSON. While LitJSON is faster than Json.NET at serialization, Json.NET is faster than LitJSON at deserialization. Meanwhile, Unity is faster than both of them!

Simply put, Unity’s new built-in JSON library is blazingly fast. If you want a quick way to boost your app’s handling of JSON, upgrade to Unity 5.3 and make the switch to JsonUtility!

What do you use for JSON? Any plans to switch when you upgrade to 5.3? Let me know in the comments!