Heap dump analysis of an OFP-related use case is showing that even though we are using ImmutableOffsetMaps to hold children, those maps still account for 2.4M (10%) objects holding 55MiB (9%) shallow memory, with additional 55MiB (9%) retained by their Object[]s.
The Object array size ranges from 2 to 12 elements, which means they have 60% to 20% overhead.
We should be able to bring these overheads down by application of runtime code generation, where we'd generate the equivalent of ImmutableOffsetMap.Unordered, where the values are stored directly in fields of the generated class. This would eliminate the need for Object[]s – i.e. 7% of heap occupancy.
Code generation should be based on Byte-Buddy, i.e. generate bytecode.
The implementation should assume NodeIdentifier addressing, i.e. the keys are strictly based on QNames. These should be destructured during internal dispatch, so that we first compare QNameModule portion (which is typically unique, but there may be others, i.e. in case of augment), then we should perform a simple switch() on localName.
The bytecode should be roughly equivalent to:
// Hand-coded base class public abstract class AbstractNodeIdentifierMap<V> extends AbstractMap<NodeIdentifier, V> implements Immutable { @Override public final V get(Object obj) { return obj instanceof NodeIdentifier nid ? get(nid.getType()) : null; } protected abstract V get(QName qname); } // Generated final class NodeIdenfierMapXXYYZZ<V> extends AbstractNodeIdentifierMap<V> { // ... for each child QNameModule private static final QNameModule MODULE0; // ... also we may need constants for QNames for things like entrySet(), keySet(), etc. // actually something reasonably-derived from QName? private final V v0_0; private final V v0_1; @Override protected V get(QName qnamej) { final var module = qname.getModule(); if (MODULE0.equals(module)) { return get0(qname.getLocalName()); } // else ... if we have more QNameModule return null; } // peeled for each QNameModule private V get0(String localName) { return switch (localName) { case "some-name" -> field0_0; case "other-name" -> field0_1; default -> null; } } }
- blocks
-
YANGTOOLS-1021 Add runtime-generated NormalizedNode implementations
- Confirmed
- relates to
-
YANGTOOLS-490 Create SchemaContext-aware NormalizedNodes
- Confirmed