For very small documents, the biggest performance gap with alternatives is
that the API impose that we allocate the State object. In a real world app
this doesn't make much of a difference, but when running in a micro-benchmark
this doubles the allocations, causing twice the amount of GC runs, making us
look bad.
However, unless we have to call a to_json method, the State object isn't
visible, so with some refactoring, we can elude that allocation entirely.
Instead we allocate the State internal struct on the stack, and if we need
to call a to_json method, we allocate the State and spill the struct on
the heap.
As a result, JSON.generate is now as fast as re-using a State instance,
as long as only primitives are generated.
Elide Generator::State allocation until a
to_json
method has to be calledFix: https://github.com/ruby/json/issues/655
For very small documents, the biggest performance gap with alternatives is
that the API impose that we allocate the
State
object. In a real world appthis doesn't make much of a difference, but when running in a micro-benchmark
this doubles the allocations, causing twice the amount of GC runs, making us
look bad.
However, unless we have to call a
to_json
method, theState
object isn'tvisible, so with some refactoring, we can elude that allocation entirely.
Instead we allocate the State internal struct on the stack, and if we need
to call a
to_json
method, we allocate theState
and spill the struct onthe heap.
As a result,
JSON.generate
is now as fast as re-using aState
instance,as long as only primitives are generated.
Before:
After: