How to determine the buffer size?
There are two radically different approaches:
- compute the buffer size from the shape of the JSON document
- use whatever amount of memory is available.
Technique 1: Compute the size from the JSON document layout
In this situation, we assume that you know what kind of input you want to parse. From that, we can predict how the JSON will be stored in memory and therefore compute the required space.
For instance, let’s say that you know in advance (and by that I mean “at compilation time”) that you want to generate an object with 3 values, one of them being an array with 2 values, like the following:
{"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
To determine the memory usage of this object tree, you use the two macros JSON_ARRAY_SIZE(n)
and JSON_OBJECT_SIZE(n)
, both take the number of elements as an argument.
For the example above, it would be:
const int BUFFER_SIZE = JSON_OBJECT_SIZE(3) + JSON_ARRAY_SIZE(2);
StaticJsonBuffer<BUFFER_SIZE> jsonBuffer;
This process is cumbersome and error-prone, that’s why there is a tool for that: the ArduinoJson Assistant. Simply paste your JSON document in the ArduinoJson Assistant and it will return the buffer size.
Don’t forget string duplication
Depending on the type of the input, the parser uses a different strategy concerning string.
If the input is mutable (ie a char*
or a char[]
), the parser assumes that the input buffer is persistent.
In that case, it stores pointers to the string in the input.
This is the “zero-copy” mode.
On the other hand, if the input is read-only (ie a const char*
, a String
or a Stream
), the parse assumes that the input is volatile.
In that case, it makes copies of the strings in the JsonBuffer
.
This obviously has an impact on the size of the JsonBuffer
The string duplication also happens when you construct use String
while constructing a JsonObject
(either as a key or as value).
So don’t forget to take this into account when you compute the JsonBuffer
size.
The ArduinoJson Assistant shows how much extra bytes are required for the string duplications.
Don’t overthink this problem
If your program computes JsonBuffer’s size at run-time, you’re trying to be too clever.
Remember why we specify the size of the buffer:
- to allocate on the stack (only for
StaticJsonBuffer
) - to reduce heap fragmentation (only for
DynamicJsonBuffer
)
You should not be looking for the exact memory consumption in each possible configuration. Instead, you should pick one size that is big enough to support all valid configurations.
If the size depends on the configuration, use the worst case scenario, and use the assistant to compute the size.
If you want an elastic size, let the DynamicJsonBuffer
grow; the simplification of the program is worth the small waste in memory.
Technique 2: Use whatever amount of memory is available.
In the second case, let’s say you dynamically generate a JSON object tree of a random complexity so you can’t put a limit based on that. But on the other hand, you don’t want your program to crash because the object tree doesn’t fit in memory. The solution is to determine how much memory is available, or in other words how much memory you can afford for the JSON object tree.