Skip to content

Performance Dictionary Key Performance

github-actions[bot] edited this page Aug 27, 2026 · 1 revision

Dictionary Key Performance

TL;DR — Do Not Hand-Write an Enum Comparer

  • Dictionary<TEnum, TValue> with the default comparer is the fastest form on Unity's Mono.
  • Supplying a hand-written struct comparer costs about 11% on every lookup.
  • This contradicts most Unity performance articles; they describe CoreCLR, where the advice was measured.

The Measurement

Both sides call TryGetValue on an eight-member enum key with values that always hit, four million lookups per slot. Measured on Unity 6000.4.6f1, Editor Mono, counterbalanced ABBABAAB runs with a settled heap per slot, per-cycle spread retained:

Key Mops/s Ratio Spread
Dictionary<TEnum, int>, default comparer 168.7 3.1%
same dictionary, hand-written struct comparer 150.2 0.8902x 1.3%

Two independent runs agreed (0.8940x, then 0.8902x).

Why the Folk Advice Fails Here

Unity's Mono BCL already ships a specialized enum comparer for enum keys, so there are no boxes to remove: EqualityComparer<ProbeKey>.Default.GetType().Name reports EnumEqualityComparer'1. What a supplied comparer does instead is move hashing and equality onto an interface the JIT cannot devirtualize or inline in this runtime — one interface call per probe, which is exactly the 11%.

The advice exists because on CoreCLR (desktop .NET), generic specialization makes supplied struct comparers fully inlined while enums sometimes fall to a slower shared path. Unity's Mono and IL2CPP are not that runtime.

Practical Rules

  • Enum keys: declare nothing. new Dictionary<TEnum, TValue>().
  • Dense id-like keys (0..N): consider an array indexed by the key first; an int[] was measured about 5x faster than any hash table at eight members.
  • Struct keys other than primitives/enums: measure before supplying a comparer; on this runtime the default is usually already specialized.
  • This package's own IntMap<TValue> exists for int keys precisely by removing all comparer indirection from its probe loop.

Caveats

All three numbers above are Editor Mono measurements; IL2CPP shares much of Mono's code-generation behavior for constrained calls but has not been re-measured here. If you re-measure on device, use a counterbalanced protocol so the machine's temperature does not answer instead of the code.

Clone this wiki locally