This page contains some tips to reduce the memory consumption when parsing a JSON document.

Avoid duplication if the input is in memory

Remember that ArduinoJson’s deserializer has two modes:

  1. the zero-copy mode, used when the input is writeable (char*)
  2. the normal mode, use when the input is read-only (const char*, String)

In the second mode, the deserializer duplicates the relevant parts of the input (basically everything except spaces and punctuation) in the JsonBuffer. So, to get the most efficient program, you must use the first mode: the zero-copy mode.

Good: zero-copy

char[] json = "{\"hello\":\"world\"}";
jsonBuffer.parseObject(json);

Bad: duplication

const char* json = "{\"hello\":\"world\"}";
jsonBuffer.parseObject(json);

Bad: duplication

String json = "{\"hello\":\"world\"}";
jsonBuffer.parseObject(json);

See also: Mastering ArduinoJson, chapter 3: Deserialize with ArduinoJson.

Pass Stream directly to the deserializer

A stream (Stream or std::istream) is a source of volatile bytes, so its content needs to be copied in RAM.

The best thing to do is to let ArduinoJson do the duplication as it ignores everything that s not required: punctuation, spaces, and comments.

To do that, simply pass the stream to parseArray() or parseObject()`.

Good: pass the Stream directly

File file = SD.open(filename);
jsonBuffer.parseObject(file);

Bad: pass a copy of the input

char buffer[256];
File file = SD.open(filename);
file.read(buffer, 256);
DynamicJsonBuffer jsonBuffer;
jsonBuffer.parseObject(buffer);

See also:

Prefer stack to heap memory

Allocating and deallocating in the heap cause overhead and fragmentation, so the program case use much less RAM that there is actually on the device. Heap allocation happens anytime you use malloc(), new and String.

ArduinoJson uses the stack with StaticJsonBuffer and the heap for DynamicJsonBuffer. For small JsonBuffer (let’s say under 1KB), prefer a StaticJsonBuffer.

If you’re using a microcontroller with very limited RAM (for example the ATmega328 of an Arduino UNO), you should not use the heap at all.

Good: only stack memory

char[] json = "{\"hello\":\"world\"}";
StaticJsonBuffer<200> jsonBuffer;
jsonBuffer.parseObject(json);

Bad: only heap memory

String json = "{\"hello\":\"world\"}";
DynamicJsonBuffer jsonBuffer;
jsonBuffer.parseObject(json);
  • Mastering ArduinoJson, chapter 2: The Missing C++ Course explains in detail what stack and heap memory, and how the various types of strings are stored.

Deserialize in chunks

One neat feature of ArduinoJson is that, when it parses an object from a Stream, it stops reading when it encounters the closing }, and the same is true for arrays.

Using this feature, you don’t have to deserialize the whole JSON document at once. Instead, you can parse only a part of it and repeat the operation.

This technique works great when your input contains an array of nested objects. For example, if you want to parse the huge response of a 10-day forecast of Weather Underground, you can skip the beginning until you see "forecastday": [ in the stream (use Stream::find()), and then parse the objects for each day one after the other.

As usual, don’t reuse the JsonBuffer, declare it inside the loop.

  • Mastering ArduinoJson, chapter 7: Case Studies contains two examples: one for OpenWeatherMap and another for Weather Underground.