The library is very well 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;

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

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

{"key":"value"}
{"key":"value"}
{"key":"value"}
{"key":null}
{"key":null}
{"key":null}
{"key":null}

As you can see, the "value" is 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 the memory. To release the memory, you must either clear or destroy the JsonDocument.

ArduinoJson uses this kind of allocator because it provides the best performance with the smallest 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.

How to fix this problem?

You can fix the above program by fixing any of the three points from the list.

Solution 1: don’t use String

ArduinoJson stores const char* and String differently. const char* are stored with a pointer (which requires no additional storage), whereas Strings are stored by copy (which requires an allocation in the JsonDocument).

So, one way to fix this program is to remove the String:

StaticJsonDocument<200> doc;

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

Solution 2: don’t use a global JsonDocument

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

void loop() {
    StaticJsonDocument<200> doc;
    doc["key"] = "value";
    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 3: clear the JsonDocument

Lastly, 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;

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