ArduinoJson 7.4: tiny string optimization
I’m excited to announce ArduinoJson 7.4, featuring a new memory optimization for embedded systems where every byte counts. This update introduces tiny string optimization that eliminates heap allocations for strings of three characters or fewer—a targeted improvement that reduces memory fragmentation and overhead in resource-constrained environments like Arduino, ESP8266, and ESP32 devices.
Tiny string optimization
Small string optimization (SSO) is a widespread optimization consisting of storing short strings in preallocated buffers to avoid a heap allocation.
This optimization is present in all implementations of std::string
and in some implementations of String
(most notably in ESP32 and ESP8266).
SSO typically covers strings up to 16 or 32 characters, but in the case of ArdunoJson 7.4, the optimization only concerns strings up to three characters; this is why I call it “tiny string optimization” instead of “small string optimization”. Also, I wanted to save the name for later.
Specifically, the three characters (and the terminator) are stored directly in the tree node (called a “slot” in ArduinoJson’s source code), whereas long strings are allocated in the heap and added to a linked list. A slot has a 4-byte payload, hence the four characters (including the terminator).
Admittedly, three characters are not much and don’t include that many strings. Still, it’s not rare to see short mnemonics, such as id
, url
, img
, ref
, lat
, lng
, etc.
Now, such a fine-grain optimization will not dramatically lower memory consumption. In most cases, the change is marginal. For instance, we only see a 0.74% decrease in the OpenWeatherMap example. However, the new version can consume half as much memory in extreme cases such as this:
["JFK","LAX","ORD","ATL","SFO","DFW","MIA","LAS"]
Even if the impact is low, it’s still good to reduce small heap allocations because they come with significant memory and time overheads. It also reduces heap fragmentation, which, as we already discussed, is crucial in embedded environments.
In addition, there is a slight performance boost because we don’t deduplicate tiny strings anymore. This avoids searching for duplicates in the string pool, which saves some CPU time.
Code size
As usual, I kept an eye on the library size to ensure the increase was on par with the improvements. In the following graphs, you can see the evolutions of the size of the ArduinoJson examples on Arduino UNO R3, an 8-bit microcontroller, and Arduino UNO R4, which is 32-bit.
Other progress
We waited three months for a new release, and all you could come up with was a 0.74% optimization. Is that all you got?
I’ve been working on a more significant memory optimization but rolled it back when I realized that the tiny-string optimization had to be done first. So, you’re right. I don’t have much to show about the ArduinoJson library.
However, in the meantime, I worked on modernizing the internals of the ArduinoJson Assistant and the ArduinoJson Troubleshooter. I also added many small features along the way. For example, you can now directly paste the compiler output to the Troubleshooter, and it will scan it to find the appropriate answer. How cool is that?
Final words
ArduinoJson is quite a mature project now, so it’s normal for the release pace to get slower. The simple optimizations have already been implemented, and the next level will require a massive amount of work, so it might take a while before I publish a new version.
Remember that you can support my work by purchasing my book or sponsoring me on GitHub. Don’t forget to subscribe to the mailing list for future updates.