Repository navigation
Kryo v6 Follow ups
Thomas Heigl edited this page Oct 14, 2026
·
20 revisions
Open items found in the reviews of kryo-6 and postponed, or still open, checked against the code on 2026-10-13. Not planned for a particular release. Decisions and done items are in Kryo v6 Ideas.
Fixes without a format change
- An application subclass of
TimeZonewithout its own default serializer is read back asTimeZone.getTimeZone(id), a different class. -
CalendarSerializercreates the writtenCalendarclass (Calendar.Builderfor the buddhist and japanese calendars) andTimeZoneSerializerthrows on write for an unknown ID instead of writing GMT. Branchcalendar-timezone, undecided because the second is a behavior change.
Format changes (gated with Format.KRYO5, golden file lengths and a MIGRATION entry)
-
Arrays.asList: a reference to the list from one of its elements resolves to the temporaryArrayList. Needs a copy ofCollectionSerializer.read(~50 lines). -
LocaleSerializerdrops the extensions of aLocalewithout a script, like Kryo 5. -
ZonedDateTimeloses the offset in a DST overlap. Write the offset and read withZonedDateTime.ofLocal(~15 lines). - The Kryo 5 format writes the registered type name (
java.util.TimeZone,java.nio.charset.Charset, enums with bodies) where Kryo 5 wrote the implementation class. Both read both. Kept so far, documented inKryo5RoundTripTest.classNameDiffers.
Performance
-
ChunkedEncoding.getlooks the encoding up in the context, a Kryo field would be +1 to 2% for chunked encoding but is an API change. - Code generation: create the object in the generated code with a constant constructor method handle, then call
kryo.referenceand read the fields in the same generated method. A prototype without the checks measured +6.8% (ObjectGraphBenchmark.field, references on) and +8.4% (references off). It may only be used when Kryo would call the zero argument constructor anyway:createnot overridden, the default instantiator strategy and no instantiator set on the registration, also if one is set later. Branchcodegen-new-ceiling, not pushed. - Code generation: batching the sets of final fields when reflection is denied. Measured on JDK 27 with a Serializable class of 10 fields: each final field costs about 150 ns per object under deny, because
FinalFieldSettersets all serializable fields of the class per call, with and without code generation (round trip with code generation 100 ns allowed, 385/835/1,590 ns denied for 2/5/10 final fields). One call per class would be about 250 ns, 1.5x to 6x faster. Idea: the generated code keeps the values of final fields in locals and sets them with one call before the next field that may refer to the object and at the end, decided when the code is generated, so no state at runtime. Deny is opt-in until a Java release makes it the default, maybe for the next LTS. Proof of concept: https://github.com/EsotericSoftware/kryo/pull/1515 (draft), 2.1x to 4.1x faster under deny with 5 to 10 final fields, ~1.15x with 2. - Shared
CachedFieldsacross Kryo instances, stage 2 of the shared metadata. The sharedFieldobjects are the big win already.
API and features
- A code generation switch on Kryo, like
kryo.setReferences, instead of aFieldSerializerFactorywith a config just to turn it on. Decide before the release.
Build, CI and release
- The README links to a
kryo-5branch that doesn't exist yet. Cut it from the last 5.x tag at the release. - OSS-Fuzz (https://github.com/google/oss-fuzz/tree/master/projects/kryo) builds master with JDK 17, which fails for Kryo 6. Fix: build with JDK 25 and copy the runtime dependencies, works for master too: https://github.com/google/oss-fuzz/pull/16284 (open, needs approval by a past contributor of the project). Optionally a fuzzer for the chunked encoding of CompatibleFieldSerializer, which the three fuzzers don't reach.
- Android: the sequenced collection wrappers on Android 35 aren't covered by tests, desugared lambdas are serialized silently with FieldSerializer (README note?), optional Kryo 5 backport of the
ExternalizableSerializerClassValuefix. - Bump the
kryo5test dependency ofKryo5RoundTripTestafter each 5.x release.
Kryo 5 line (master)
- The IO fixes https://github.com/EsotericSoftware/kryo/pull/1357, https://github.com/EsotericSoftware/kryo/pull/1365, https://github.com/EsotericSoftware/kryo/pull/1366, https://github.com/EsotericSoftware/kryo/pull/1367 and https://github.com/EsotericSoftware/kryo/pull/1370 exist only on kryo-6. Master's
Outputstill overflowscapacity * 2above 1 GiB. - Ports of https://github.com/EsotericSoftware/kryo/pull/1473 (nested objects of the same generic class), https://github.com/EsotericSoftware/kryo/pull/1475 (references resolve to the returned object), https://github.com/EsotericSoftware/kryo/pull/1495 (instantiator fallback), https://github.com/EsotericSoftware/kryo/pull/1498 (field settings changed by unknown field data), https://github.com/EsotericSoftware/kryo/pull/1504 (negative collection and map sizes), https://github.com/EsotericSoftware/kryo/pull/1505 (
ByteBufferOutput.setBufferoffset and count), https://github.com/EsotericSoftware/kryo/pull/1506 (isAssignableToforvoid.class) and the zip, OSGi and Dependabot parts of https://github.com/EsotericSoftware/kryo/pull/1490. Kryo 5 has all these bugs. - The chunked encoding of CompatibleFieldSerializer in Kryo 5 can't skip a removed field that contains nested chunked objects with a longer string (buffer underflow on 5.7.1, second half of
ChunkedEncodingTest.testLargeFields).