Skip to content

fix(hub): track and cut the per-hub DI and type-metadata cost — a burst of hub activations can OOM a 12 GiB portal replica #7385

Closed

Description

@systemorph

The per-hub cost of DI and type metadata has no open tracker, and on 2026-10-23 it turned one UI click into an out-of-memory crash of a portal replica.

Evidence (governed AnalyzeDump, control instance, Ops/Actions/i7082-analyzedump-hwx6z-heapstat, page Ops/Dumps/i7082-analyzedump-hwx6z-heapstat; memex pod hwx6z, dump written 2026-10-23T08:03:15Z, read with core main cdf9bf0):

  • Managed heap 12,319,278,588 bytes, 203.1 M objects. Gen2 11.08 GiB, compacted; SOH free 0 %, so this is live retained memory and not fragmentation.
  • Autofac child-scope rows: 5.78 GiB (50.3 %). MiddlewareDeclaration 2.44 GB (50.8 M objects); ExternalComponentRegistration 1.35 GB (12.06 M), plus its NoOpActivator 0.29 GB; ResolvePipelineBuilder 0.50 GB (12.4 M); Service[] 0.40 GB; ConcurrentQueueSegment+Slot[] 0.45 GB.
  • Per-hub TypeRegistry rows: 1.49 GiB (13 %). TypeDefinition 2.79 M with its Lazy/Lazy/Func/LazyHelper; ConcurrentDictionary<String,TypeDefinition>+Node 4.69 M.
  • No application data type is in the top 30.
  • 2,568 Orleans activation message loops were live. That is about 4,700 external registrations and about 1,090 type definitions per activation, and the heap grew about 3.6 MB per activation (2.1 to 11.3 GiB). That matches the ~5 MB per node hub in MeshWeaver#6623.

Code path: ServiceProviderExtensions.SetupModules calls BeginLifetimeScope(c => PopulateMeshWeaverWithOwners(...)) for every hub. A configuration action gives the child scope its own registry, and that registry wraps each parent registration it touches in an ExternalComponentRegistration with a ~4-stage pipeline. MessageHubConfiguration also builds a TypeRegistry per hub, which holds its own TypeDefinition per registered type. #5925 only shares the display metadata.

This is defect 3 of Doc/Architecture/PortalHeapIsHubs ("a hub costs ~390 KB, ~173 KB of it duplicated framework metadata"). That page measured 262 external registrations per hub in September. Its trackers MeshWeaver#3321 and #3432 are closed, and #6623 (sev:L) covers only boot-activated hubs. The trigger on 2026-10-23 is fixed by MeshWeaver.Plugins#4112 (the mark-all-read fan-out). Fixing the trigger leaves any burst of a few thousand hub activations, from any caller, able to exhaust a 12 GiB heap, because each hub costs megabytes of identical framework metadata.

Not established: the MessageHub count in this dump (MessageHub is not in the 30 rows kept). So it is not known whether registrations per hub grew since September or hubs per activation grew. Retention by referrer (no gcroot) is also not established; the attribution to hub scopes is from types and code, not from a root walk.

Analysis comment: MeshWeaver#7082 issuecomment-6382995136.

Where: submitted from the portal Feedback module on memex.systemorph.com; no main node attached.
Owner basis: the named symbols ServiceProviderExtensions.SetupModules, PopulateMeshWeaverWithOwners and MessageHubConfiguration are MeshWeaver core — they are the subject of Systemorph/MeshWeaver PRs #7027 and #7131 — and every tracker the report cites (#3321, #3432, #5925, #6623, #7082) is a Systemorph/MeshWeaver issue; #6623 measured the same ~5 MB per node hub.
Related: PR #7131 (fix(hub): a hub scope no longer re-declares its ancestors' instances or the mesh's type definitions) is in flight on this exact cost — this issue is the open tracker the report asks for.
Origin: https://memex.systemorph.com/Feedback/_Submissions/fb-82f9c96856254c5a0837d7953fb48eb5 (submitted on memex.systemorph.com)

filed by the triage agent on behalf of rbuergi via systemorph-com


Triage routing: filed in Systemorph/MeshWeaver — agent: Systemorph/MeshWeaver — Symbols ServiceProviderExtensions.SetupModules / PopulateMeshWeaverWithOwners / MessageHubConfiguration are MeshWeaver core (subjects of MeshWeaver PRs #7027 and #7131); all cited trackers (#3321, #3432, #5925, #6623, #7082) are Systemorph/MeshWeaver issues..

Activity

  1. added
    bugSomething isn't working
    sev:HBLOCKING: primary path broken, intermittent user-visible failure, or silently wrong results.
    on Oct 27, 2026
  2. rbuergi commented on Oct 27, 2026

    @rbuergi
    Contributor

    The two cost rows the dump measured are addressed on main:

    The triage note's "#7131 in flight" is stale. The running image 94cfc71adb contains all three. Awaiting post-roll verification: a heap reading (per-activation growth, or a governed AnalyzeDump) on the running image that shows the per-hub framework metadata gone. Leaving open.

  3. rbuergi commented on Oct 29, 2026

    @rbuergi
    Contributor

    Deployed; behaviour not verifiable read-only. Leaving open.

  4. rbuergi commented on Nov 1, 2026

    @rbuergi
    Contributor

    Verified on production with the instrument this issue names (a governed AnalyzeDump on a post-fix image). Closing.

    The reading: Ops/Dumps/t1031-5388-analyzedump-dsfp6 on the control instance. It is a dump of memex pod memex-portal-deployment-86f575cbd7-dsfp6, written 2026-10-30 19:03Z and analysed 2026-10-31 17:39Z.

    The build: the pod's own warm-up line (Ops/Actions/iss7385-dsfp6-commit, 2026-10-30 12:19:53Z) reads platform build 3.1.12166 … commit g1a63da9724. Compared against 1a63da9724, the merge commits of #7131 (8478c800), #7147 (2cc600e3) and #7167 (f531a285) all return ahead. So the pod ran all three fixes.

    What the dump shows, against the original reading from hwx6z:

    Row family hwx6z (pre-fix, 2026-10-23) dsfp6 (3.1.12166, 2026-10-30)
    Autofac child-scope rows (MiddlewareDeclaration, ExternalComponentRegistration, ResolvePipelineBuilder, …) 5.78 GiB (50.3 %) absent. Autofac is no longer in the process (#7147)
    Per-hub TypeDefinition + ConcurrentDictionary<String,TypeDefinition> 1.49 GiB (13 %) absent from the top 40 types. The smallest row shown is 11.6 MB

    For scale: dumpasync counts 89 Orleans activation message loops in dsfp6. At the hwx6z rates, 89 activations would carry roughly 85 MB of MiddlewareDeclaration and roughly 50 MB of TypeDefinition rows. Either would rank in the top 40, and neither does.

    Not established:

    • This is not a burst of a few thousand activations, so the "stays well below 12 GiB under such a burst" half was not exercised.
    • MessageHub itself is not in the 40 rows kept, so per-hub cost was not computed directly.

    A different retention is in this dump: 12.3 GB on the heap, 48.8 % of it Free, about 2.42 M retained GetDataRequest deliveries and their HubStreamProviderFactory SelectMany chains, and a StackOverflowException in SelectMany…InnerObserver.OnError. That is a content-collection resolution cycle, not the per-hub framework metadata this issue tracks. The fix is in #7763.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfeedbacksev:HBLOCKING: primary path broken, intermittent user-visible failure, or silently wrong results.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions