Table of Contents

Class MemoryProfiler

Namespace
PopcorningGuineaPig.Engine.Diagnostics
Assembly
PopcorningGuineaPig.Engine.dll

Game-side, opt-in memory profiling API. Produces MemorySnapshot values that are bit-comparable with editor-side snapshots from Story 12.2, so the same diff tooling works against both editor and game captures.

public sealed class MemoryProfiler
Inheritance
MemoryProfiler
Inherited Members

Remarks

Lives in the engine assembly so a shipped game can opt in without referencing the editor or ImGui. By design, the type is referenced lazily through Default or constructor injection — if game code never touches either, the trimmer (Story 12.1) strips MemoryProfiler and its sinks from the published distributable.

Thread contract: Snapshot(string) reads IAssetRegistry dictionaries and process counters. Call only when the registry is not being mutated — i.e. between frames on the main thread, or from the periodic-sampling worker that StartPeriodicSampling(int, IMemorySink, CancellationToken) launches (the worker takes the same constraint).

Constructors

MemoryProfiler(IAssetRegistry, ILogger<MemoryProfiler>?)

Creates a new profiler bound to the supplied registry. Construct one of these directly if your game does its own service composition; otherwise use Default for a lazy singleton over Game.Instance.AssetRegistry.

public MemoryProfiler(IAssetRegistry assetRegistry, ILogger<MemoryProfiler>? logger = null)

Parameters

assetRegistry IAssetRegistry

The asset registry to introspect. Must not be null.

logger ILogger<MemoryProfiler>

Optional logger for warnings (e.g. snapshot exceeded 50ms budget).

Properties

Default

Lazy singleton that resolves Instance's asset registry on first access. Returns the same instance for every subsequent call. If game code never touches this property (or new MemoryProfiler(...)) the trimmer can strip the entire diagnostics surface.

public static MemoryProfiler Default { get; }

Property Value

MemoryProfiler

Exceptions

InvalidOperationException

Thrown if no Game.Instance is available when first accessed.

Methods

Snapshot(string)

Captures a point-in-time memory snapshot. Walks the asset registry and reads GC + process counters.

public MemorySnapshot Snapshot(string description)

Parameters

description string

Free-form label stored on the snapshot (e.g. "after-level-load", "manual").

Returns

MemorySnapshot

Remarks

Allocates ~1 KB per call. Bounded at < 50 ms on a project with ~1000 assets. Do NOT call from per-frame gameplay code — see StartPeriodicSampling(int, IMemorySink, CancellationToken) for the on-an-interval pattern.

StartPeriodicSampling(int, IMemorySink, CancellationToken)

Starts a background task that takes a snapshot every intervalMs milliseconds and forwards it to sink. Cancellable via StopPeriodicSampling() or the optional ct.

public Task StartPeriodicSampling(int intervalMs, IMemorySink sink, CancellationToken ct = default)

Parameters

intervalMs int

Milliseconds between snapshots. Must be ≥ 10.

sink IMemorySink

Where to forward each snapshot.

ct CancellationToken

Optional external cancellation; combined with the internal one.

Returns

Task

The worker task. Subscribe for completion or exceptions if you care.

Remarks

Snapshots run on a worker thread, not the game's main thread. The cost on the main thread is only the brief asset-registry reads (which the registry is contract-bound to permit between frames). Calling this a second time without first calling StopPeriodicSampling() replaces the previous sampling task.

StopPeriodicSampling()

Cancels any in-flight periodic sampling. Idempotent — safe to call when no sampling task is running.

public void StopPeriodicSampling()

WriteToFile(MemorySnapshot, string)

Convenience helper: serialize snapshot to JSON and write it to path. Uses JsonOptions so the on-disk format is stable across framework default changes.

public static void WriteToFile(MemorySnapshot snapshot, string path)

Parameters

snapshot MemorySnapshot
path string