Reputation: 2453
I'm trying to use Json.net to serialize and deserialize objects in a windows universal project. I need to use this library in a background task and as memory for background tasks is very limited on windows phone I need to make sure that I'm not using too much memory.
The problem I'm having is that Json.net seems to use a lot of memory that never seems to get freed.
To demonstrate this I have created a small example. Create a new universal app and create an PageLoaded event handler as follows (this example is the same in a windows app as it is in a phone app so it doesn't matter which platform you use):
private void Page_Loaded(object sender, RoutedEventArgs e)
{
List<string> testItems = new List<string>();
List<string> destinationItems;
testItems.Add("Test Item Number 001");
testItems.Add("Test Item Number 002");
testItems.Add("Test Item Number 003");
testItems.Add("Test Item Number 004");
testItems.Add("Test Item Number 005");
testItems.Add("Test Item Number 006");
testItems.Add("Test Item Number 007");
testItems.Add("Test Item Number 008");
testItems.Add("Test Item Number 009");
testItems.Add("Test Item Number 010");
testItems.Add("Test Item Number 011");
testItems.Add("Test Item Number 012");
testItems.Add("Test Item Number 013");
testItems.Add("Test Item Number 014");
testItems.Add("Test Item Number 015");
testItems.Add("Test Item Number 016");
testItems.Add("Test Item Number 017");
testItems.Add("Test Item Number 018");
testItems.Add("Test Item Number 019");
testItems.Add("Test Item Number 020");
testItems.Add("Test Item Number 021");
testItems.Add("Test Item Number 022");
testItems.Add("Test Item Number 023");
testItems.Add("Test Item Number 024");
testItems.Add("Test Item Number 025");
testItems.Add("Test Item Number 026");
testItems.Add("Test Item Number 027");
testItems.Add("Test Item Number 028");
testItems.Add("Test Item Number 029");
testItems.Add("Test Item Number 030");
testItems.Add("Test Item Number 031");
testItems.Add("Test Item Number 032");
testItems.Add("Test Item Number 033");
testItems.Add("Test Item Number 034");
testItems.Add("Test Item Number 035");
testItems.Add("Test Item Number 036");
testItems.Add("Test Item Number 037");
testItems.Add("Test Item Number 038");
testItems.Add("Test Item Number 039");
testItems.Add("Test Item Number 040");
testItems.Add("Test Item Number 041");
testItems.Add("Test Item Number 042");
testItems.Add("Test Item Number 043");
testItems.Add("Test Item Number 044");
testItems.Add("Test Item Number 045");
testItems.Add("Test Item Number 046");
testItems.Add("Test Item Number 047");
testItems.Add("Test Item Number 048");
testItems.Add("Test Item Number 049");
testItems.Add("Test Item Number 050");
testItems.Add("Test Item Number 051");
testItems.Add("Test Item Number 052");
testItems.Add("Test Item Number 053");
testItems.Add("Test Item Number 054");
testItems.Add("Test Item Number 055");
testItems.Add("Test Item Number 056");
testItems.Add("Test Item Number 057");
testItems.Add("Test Item Number 058");
testItems.Add("Test Item Number 059");
testItems.Add("Test Item Number 060");
testItems.Add("Test Item Number 061");
testItems.Add("Test Item Number 062");
testItems.Add("Test Item Number 063");
testItems.Add("Test Item Number 064");
testItems.Add("Test Item Number 065");
testItems.Add("Test Item Number 066");
testItems.Add("Test Item Number 067");
testItems.Add("Test Item Number 068");
testItems.Add("Test Item Number 069");
testItems.Add("Test Item Number 070");
testItems.Add("Test Item Number 071");
testItems.Add("Test Item Number 072");
testItems.Add("Test Item Number 073");
testItems.Add("Test Item Number 074");
testItems.Add("Test Item Number 075");
testItems.Add("Test Item Number 076");
testItems.Add("Test Item Number 077");
testItems.Add("Test Item Number 078");
testItems.Add("Test Item Number 079");
testItems.Add("Test Item Number 080");
testItems.Add("Test Item Number 081");
testItems.Add("Test Item Number 082");
testItems.Add("Test Item Number 083");
testItems.Add("Test Item Number 084");
testItems.Add("Test Item Number 085");
testItems.Add("Test Item Number 086");
testItems.Add("Test Item Number 087");
testItems.Add("Test Item Number 088");
testItems.Add("Test Item Number 089");
testItems.Add("Test Item Number 090");
testItems.Add("Test Item Number 091");
testItems.Add("Test Item Number 092");
testItems.Add("Test Item Number 093");
testItems.Add("Test Item Number 094");
testItems.Add("Test Item Number 095");
testItems.Add("Test Item Number 096");
testItems.Add("Test Item Number 097");
testItems.Add("Test Item Number 098");
testItems.Add("Test Item Number 099");
testItems.Add("Test Item Number 100");
Debug.WriteLine(GC.GetTotalMemory(true));
string saveStr = JsonConvert.SerializeObject(testItems);
Debug.WriteLine(GC.GetTotalMemory(true));
destinationItems = JsonConvert.DeserializeObject<List<string>>(saveStr);
Debug.WriteLine(GC.GetTotalMemory(true));
destinationItems = null;
Debug.WriteLine(GC.GetTotalMemory(true));
}
The debug output is:
40236
193084
199624
193472
I would expect the last value to approximately match the first value but it seems that Json.net holds onto about 150kb of memory. What's more, subsequent serialisation and deserialisation instructions seem to make the situation worse.
I've not tried this in a windows desktop app but I would expect the results to be the same.
My questions are: Does anyone know why this is happening and how to free up this memory? If this is not possible, does anyone know of another Json library that manages memory better?
Edit: After battling with this for some time, I realised that the problem was not Json.net but an issue with streams in WinRT.
I've asked a new question on MSDN (hoping that someone at Microsoft might be able to explain it) here: WinRT Stream Memory Issue
Upvotes: 4
Views: 1303
Reputation: 2888
As far as I know there is no guarantee that the GC actually have recycled all unused objects when you invoke GC.GetTotalMemory(true). You will need to test this for a longer duration with more data to be sure that there is an actual memory leak.
I am pretty certain that JSON.NET caches generated serializers/deserializers for performance reasons and they will not be reclaimed in this scenario. However the actual amount of memory used should not increase during continuous serialization/deserialization of previously serialized/deserialized types.
Upvotes: 3