Skip to content

[Perf] Lazy-initialize _triggerSpecificity dictionary on BindableObject #34131

@simonrozsival

Description

@simonrozsival

Summary

Every BindableObject eagerly allocates a Dictionary<TriggerBase, SetterSpecificity> at construction time, even though the vast majority of objects never use triggers. Lazy-initializing this field would eliminate a per-object heap allocation for all trigger-free elements.

Current behavior

internal Dictionary<TriggerBase, SetterSpecificity> _triggerSpecificity = new Dictionary<TriggerBase, SetterSpecificity>();

The dictionary is only accessed from TriggerBase attach/detach/query:


bindable._triggerSpecificity[this] = specificity;

((SealedList<TriggerAction>)EnterActions).IsReadOnly = true;

In a typical app, triggers are used on <5% of visual elements, but every Label, Button, Grid, StackLayout, etc. pays the allocation cost.

Proposed change

Lazy-initialize on first use:

// Before
internal Dictionary<TriggerBase, SetterSpecificity> _triggerSpecificity = new Dictionary<TriggerBase, SetterSpecificity>();

// After
internal Dictionary<TriggerBase, SetterSpecificity>? _triggerSpecificity;

The three call sites in TriggerBase.cs need minor updates:

  • Attach (line 83): (bindable._triggerSpecificity ??= new()).Add(this, specificity)
  • Detach (line 93): bindable._triggerSpecificity?.Remove(this)
  • Query (line 109): bindable._triggerSpecificity?.TryGetValue(this, out var specificity) == true

Estimated impact

An empty Dictionary<TriggerBase, SetterSpecificity> costs ~100 bytes. For a page with 200 elements: ~20 KB saved per page load.

Metadata

Metadata

Assignees

No one assigned

    Labels

    perf/generalThe issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions