The library is thoroughly tested; it’s is very unlikely that you found a memory leak. You’re probably using the library incorrectly.

What’s the problem?

The “leak” appears when you reuse a JsonDocument without destroying or clearing it. Here is an example that shows this “leak”:

StaticJsonDocument<200> doc;
int counter;

void loop() {
  doc["key"] = String("value") + counter++;
  serializeJson(doc, Serial);
}

If you run this program, you’ll see something like this:

{"key":"value0"}
{"key":"value1"}
{"key":"value2"}
{"key":null}
{"key":null}
{"key":null}
{"key":null}

As you can see, all values after "value3" are missing, showing that the JsonDocument ran out of space.

Why does this happen?

JsonDocument contains a monotonic allocator: a fast and lightweight allocator that cannot release memory. To release memory, you must either clear or destroy the JsonDocument.

ArduinoJson uses this kind of allocator because it provides the best performance with the smallest possible code. Most users don’t notice the problem, but you can run into it if you reuse the same JsonDocument without destroying or clearing it.

The program above runs out of memory because:

  1. It uses a String, forcing ArduinoJson to make a copy.
  2. It uses a global JsonDocument.
  3. It doesn’t clear the JsonDocument between each iteration.

ArduinoJson is a serialization library: it is designed to serialize and deserialize JSON documents.
Do not use a JsonDocument not to store the state of your application.

How to fix this problem?

Solution 1: don’t use a global JsonDocument

The “leak” would not be a problem if the program were not reusing the same JsonDocument.
Instead, it could just create a new one each time, like so:

int counter;

void loop() {
  StaticJsonDocument<200> doc;
  doc["key"] = String("value") + counter++;
  serializeJson(doc, Serial);
}

If you use a StaticJsonDocument, like the example above, there is virtually no impact on the performance because creating and destroying a StaticJsonDocument is extremely fast.

Solution 2: clear the JsonDocument

We can eliminate the problem by releasing the memory at the beginning of each iteration.
To do that, simply call JsonDocument::clear(), as in the snippet below:

StaticJsonDocument<200> doc;
int counter;

void loop() {
  doc.clear();
  doc["key"] = String("value") + counter++;
  serializeJson(doc, Serial);
}

Solution 3: call garbageCollect()

If it’s not possible to clear the document, you can call JsonDocument::garbageCollect() to reclaim the leaked memory.

StaticJsonDocument<200> doc;
int counter;

void loop() {
  doc["key"] = String("value") + counter++;
  doc.garbageCollect();
  serializeJson(doc, Serial);
}

Internally, this function creates a copy of the document and replaces the original, so it’s a slow operation and temporarily requires a lot of memory.

See also