Conversation
Move HDF5 entity metadata from the data runnable into AgentDataSubsystem (CachedHdf5Entities) so entity info remains available after runnable teardown. Update SetEntityInfoByIndex and SetEntityRenderingByIndex to read from the cached subsystem array. Release the raw HDF5 sample buffer earlier in Run() to reduce peak memory usage. In MassEntitySpawnSubsystem: - add RegisteredPedestrianTemplateID - explicitly DestroyTemplate on file switch to prevent stale FSimulationFragment references from being retained in the TemplateRegistry - clear SharedSimulationFragment before recreating it - use MoveTemp when creating shared fragments Also cache HDF5 entities during BuildPedestrianMovementFragmentData, reset JSONObject where appropriate, and apply minor cleanup/comment improvements. Note: This change mitigates the current suspected lifetime/memory issue, but it does not complete the larger loading/parsing overhaul. A follow-up refactor is planned once the current issue is resolved to separate format-specific loading from the shared data parsing path. That will allow JSON, HDF5, and future formats to produce a consistent intermediate representation, reducing duplicated logic, limiting format-specific assumptions, and making eventual streaming support significantly easier to implement. AI transparency: Claude assisted with investigation of the suspected issue and potential fixes. ChatGPT was used to polish the wording of this commit message. All code changes and final review decisions remain mine.
Introduce a lightweight memory-tracing helper (MemoryTraceHelper.h) and instrument key places (AgentDataSubsystem, MassEntitySpawnSubsystem, runnable lifecycle) with FMobiusMemSnapshot to diagnose allocation/regression issues (compiled out in Shipping). Unify simulation-entity paths by extracting JSON entity rows into Hdf5Data.Entities and renaming CachedHdf5Entities to CachedEntityData; remove legacy JSON-only fallback code and simplify entity parsing paths to avoid dangling JSONObject lifetimes. Add a ProjectMobiusTests module with automated memory tests (simulation fragment lifecycle, reload cycles, and entity cache lifecycle) and register the tests; update .uproject to include the new tests module and add the module Build.cs. Minor logging and cleanup improvements around runnable/switch/gc points to help track memory during loads and teardown. Memory management is better but still need to address it further. Used Claude to generate text memory logger.
Wraps up the FSimulationFragment heap indirection started in the previous commit. SimulationData is now a TSharedPtr<TMap> so the ~4 GB block can be freed on file switch without waiting for the Mass archetype that permanently holds the fragment struct. Updated every call site that poked the member directly - PedestrianInitializeMOP, PedestrianMovementProcessor, AgentDataSubsystem (JSON + HDF5 paths), MassEntitySpawnSubsystem, FloorStatsWidget. MassEntitySpawnSubsystem now runs a second GC pass after clearing the template, and the processing runnable ends with FMemory::Trim() so pages actually return to the OS. Added a few FMobiusMemSnapshot probes around the Juelich convert and flow-counter reset for delta tracking. Used Claude (AI) to re-audit FlowCounter.cpp / StatisticSubsystem.cpp after the earlier HasAgentBeenCountedInFlowCounter nullptr fix to identify any other potential issues of the same shape. It turned up several - IsAgentLocationInAFlowCounterBand, SendDataToFlowCounter and SendArrayDataToFlowCounter were all missing the IsActorBeingDestroyed guard; the FlashBarrierColor timer captured raw this and was never cleared in EndPlay (now WeakObjectPtr + EndPlay cleanup); and GetHoveredAgentInfoMeshData was quietly MoveTemp-ing its backing member, so a second read per update returned default-constructed data (now a plain copy, matching the Selected equivalent). Added null guards on the pillar meshes and trigger box, and tagged the two GT-only reader paths with comments so a future non-GT caller will trip a visible reminder instead of a race. Deleted dead code the audit surfaced: unused StatisticSubsystem TObjectPtr on AFlowCounter, ThreadSafeNewAgentDataQueue + its FBuckectTempData struct, a stale BucketData copy inside a hot loop, and a block of commented-out AsyncTask scaffolding in SendArrayDataToFlowCounter. Project config: ProjectMobiusTests moved to Editor type with AutomationController added so automation macros load in editor builds. DefaultGame.ini flipped CrashReporter on and ForDistribution off for dev iteration. RightBracket added as an extra console key.
Instrument memory tracing and improve async/thread safety across multiple systems. Key changes: - Add and include Util/MemoryTraceHelper and define LogMobiusMemory for MobiusCore; add FMobiusMemSnapshot probes in FlowCounter, StatisticSubsystem, StatisticActorManagementSubsystem, MassEntitySpawnSubsystem and AgentDataSubsystem to help diagnose memory retention during file switches and lifecycle operations. - HeatmapSubsystem: snapshot Heatmaps into TWeakObjectPtr arrays for safe iteration on worker threads and re-validate actors before use. - RuntimeMeshBuilder: reuse RuntimeDatasmithAnchor (call Reset), guard async work with TWeakObjectPtr, and capture ExistingRunnable by value when dispatching deletion to the game thread. - MobiusIpcClient: marshal OnMessage delegate execution to the game thread using AsyncTask and a weak/shared pointer check to avoid touching UObject state from background thread. - AgentDataSubsystem: add ClearPerFileState to drop per-file caches and drain queues between file switches. - Add MobiusCore dependency to ProjectMobiusTests.Build.cs so tests can access the new utilities. Overall the patch is focused on reducing transient UObject retention, eliminating race conditions in background tasks, and providing runtime memory diagnostics to trace leaks and allocator behavior.
Fixed several significant memory leaks occurring when switching between .udatasmith, .ifc, and .fbx files. These fixes reduce the process-memory delta per switch from ~749 MB to ~303 MB. Core Datasmith & Runtime Fixes Plugged the "Deferred-Purge" Race: Instead of destroying and re-spawning ADatasmithRuntimeActor (which deferred EndPlay and kept ~840 UObjects rooted), we now reuse the actor across loads. Implemented Two-Tick Deferral: Added a two-tick delay after calling Reset() to ensure FSceneImporter::Tick completes its cleanup before the next import starts. A single tick was found to be insufficient due to FTimerManager execution order. Proactive Garbage Collection: Forced a CollectGarbage sweep at the start of the load continuation to prevent the memory footprint from doubling before the engine's natural GC cycle. Actor & Component Cleanup Material & Timer Leaks: Fixed leaks in AFlowCounter (MIDs) and UScreenFacingWorldWidgetComp (Active timers) by explicitly clearing them in EndPlay. Visualizer Optimization: Fixed a monotonic growth bug in HeatmapPixelTextureVisualizer where the index buffer (MeshTriangles) was never emptied. Thread Safety: Switched to TWeakObjectPtr for async mesh builds to prevent crashes or leaks if an actor is destroyed mid-build. Logic & Subsystem Fixes Buffer Drains: Fixed a bug where MeshLoaderRunnable was nulled without being deleted, causing massive leaks in ProceduralMeshComponent buffers. Subsystem Resets: Added ResetForFileSwitch hooks to the Statistics and Widget subsystems to clear agent data and unbind delegates, preventing dangling references to destroyed widgets. Verification Results: Live Refs: Confirmed via FReferenceChainSearch (dropped from 838 to 1). Stability: Confirmed flat object counts for BoxComponent and DeformableQuadComponent across multiple switches. Memory: Residual growth in obj list is now confirmed as PendingKill assets awaiting engine GC, not active leaks. Will assess current blueprint code for any missed object/delegate cleanups AI Usage: Claude was used to identify potential leak sights, reading debug profiling logs and assist with patches a notable patch was moving from an object to a TWeakObjectPtr in HeatmapPixelTextureVisualizer.cpp
Add ReleaseDatasmithSceneResources() and call it from EndPlay to flush rendering commands, detach static mesh components, clear physics meshes, release render resources and wait on fences so heavy GPU/CPU buffers owned by DatasmithRuntime are freed. Move MasterTypeCache to a class-level static (and clear it on EndPlay) so UMaterial* entries don't become stale across PIE sessions; clear DatasmithMaterialsMap and destroy the RuntimeDatasmithAnchor. Also include minor header/formatting cleanups. Additionally add/import updated splash/icon assets and PNG variants, and set ProjectDisplayedTitle="Mobius Viewer" in DefaultGame.ini. UAsset LFS blobs updated accordingly.
Remove dynamic binding to GameInstance (OnPedestrianVectorFileUpdated) in UMassEntitySpawnSubsystem::Deinitialize by checking GetMobiusGameInstance(GetWorld()) and calling RemoveDynamic before Super::Deinitialize to avoid dangling callbacks. Also update Git LFS OIDs/sizes for BP_MobiusPawn.uasset and BP_ProjectMobiusController.uasset (asset blob changes).
Add a TWeakObjectPtr<UProjectMobiusGameInstance> CachedGameInstance to store the game instance when binding OnPedestrianVectorFileChanged. Set the cache in GetScreenshotRequiredSubsystemsAndData when casting succeeds, and use it in EndPlay to RemoveDynamic and clear the cached pointer. This removes the GetWorld()-based lookup and ensures safe unbinding/cleanup of the delegate.
the toggle text would change from on and off, the feature made sense to me at the time but ultimately is confusing and lead to users turning on and off debug features repeatedly as they were unsure what state the toggle meant when on or off
Replace hard thread kills and manual Exit() calls with proper join/wait semantics to avoid Assimp/HDF5 leaks and race conditions (WaitForCompletion in destructors, remove manual Exit()). Drop stale delegate bindings before stopping runnables and bind completion delegates before starting new runnables to avoid late broadcasts reaching freed/stale state. Reset runnable pointers and data-load flags (bIsDataLoaded) when switching files to prevent using previous-run data. Make async/game-thread interactions safer: use TWeakObjectPtr in ParallelFor->AsyncTask closures for HeatmapSubsystem spawns, and guard CreateHeatmap calls behind weak-pointer validity checks. Fix widget lifecycle for AgentInfoDisplay: move slate resource release/cleanup to ReleaseSlateResources/RebuildWidget, rebind delegates in RebuildWidget, and remove BeginDestroy override. Add null/IsValid checks and early returns in various MassAI processors (heatmap/time-dilation/niagara) to prevent crashes when subsystems or actors are missing. Also minor whitespace/license formatting cleanup. Overall these changes reduce crashes, memory leaks, and race conditions when stopping/starting background runnables and interacting with game-thread subsystems.
Discovered the edited resolutions sizes did not transfer over correctly, have since corrected this and sharpened the image with the assist of ChatGPT to sharpen the image
Refactor heatmap and runtime mesh building to emit geometry in multiple sections and pump those sections across frames to avoid large game-thread hitches. Adds tile-based mesh construction, per-tile/per-section material assignment, and a ticked EmitNextTileSection/EmitNextChunkSection flow with FinalizeTileEmit/FinalizeMeshEmit to stagger CreateMeshSection calls. Introduces SplitSubmeshByTriCap and submesh chunking to cap tris per section, enables async cooking for procedural meshes, defers Datasmith heatmap broadcast until components are ready, and adds detailed timing/logging via UMobiusCustomLoggerSubsystem. Also hardens checks for multi-section meshes, cleans up ticker handles in EndPlay, and preserves legacy single-section fallback when batching is disabled.
Add adaptive door spawn strategy and safer async/memory handling across the project. Key changes: - RuntimeMeshBuilder: cancel in-flight FBX tickers and async runnables during mesh resets, guard late async callbacks, abort stale spawner entries, and call DecideAndExecuteSpawnStrategy after Datasmith load. - New DecideAndExecuteSpawnStrategy: consults PerformanceUtilSubsystem (instant + smoothed FPS) and physical memory to choose between immediate flush or batched spawning; reports a user warning and logs when batched mode is used. Added SpawnFPSThreshold and MemFreeThreshold tunables. - FlowCounterSpawnerComponent: add FlushRemainingSpawns() to bypass frame throttles and AbortSpawning() to discard queued doors; wire AbortSpawning() call from mesh reset. - PerformanceUtilSubsystem: add SmoothedFPS and accessors, compute smoothed FPS in CalculateCurrentFPS, and expose getters for use by spawn logic. - MobiusCustomLoggerSubsystem: adjust FlushToDisk ordering and emit a warning log when logging is disabled; ensure flush delegate broadcasting remains. - FlowCounterWidget: make geometry handling robust (use MyGeometry from NativeTick), move style update into an internal function, improve sizing/measurement and early-exit checks. - Mass AI / Agent data: add timing logs around runnable creation and deserialization, remove unnecessary sleeps, add optional file-switch diagnostics, improve GC/trim sequencing, ensure SimulationData backing map is emptied before resetting shared pointer, and stabilize spawned handle cleanup. - MassEntitySpawnSubsystem: opt-in diagnostics and safer teardown flow during file switches; minor logging and housekeeping improvements. - Agent data runnable: small logging/timing instrumentation for performance debugging. - UI/Error window: increase default size. - Tests: add FSimulationFragmentSharedBackingClearTest to verify clearing the shared backing map behavior. These changes aim to prevent stale async work from re-adding old geometry, reduce memory retention during data/file switches, and make door-flow spawning adaptive to runtime performance and memory conditions while providing diagnostic hooks for investigation.
removed trim, from the thread data importer, calling trim on a non game thread is not allowed and will trigger assertion fails
Promote EditorScriptingUtilities to the public deps of MobiusEditor and remove the MobiusWidgets module from ProjectMobius. Remove direct includes for HeatmapVisualization and TimeDilation from AgentDataSubsystem, and remove MobiusWidgetSubsystem usage and reset in MassEntitySpawnSubsystem (still reset StatisticSubsystem). Also apply minor formatting/whitespace cleanups in build files. These changes reduce coupling to widget/heatmap subsystems and adjust dependency visibility.
Remove the EditorScriptingUtilities dependency and replace usages of UEditorAssetLibrary with asset-registry / ObjectTools / AssetTools helpers. MobiusEditor.Build.cs: drop "EditorScriptingUtilities" from public deps. GenerateDatasmithMaterialsCommandlet.cpp: add includes (AssetToolsModule, IAssetTools, ObjectTools), implement AssetExists, DeleteAssetAtPath, DuplicateAssetToPath helpers, and replace all UEditorAssetLibrary checks/Deletes/Duplicate calls with the new helpers. MobiusEditorModule.cpp: replace UEditorAssetLibrary existence checks with AssetRegistry::GetAssetsByPackageName checks. This keeps asset operations behavior while removing the EditorScriptingUtilities plugin dependency.
|
All validation tests have been completed successfully. Additional testing on legacy hardware is still recommended to ensure acceptable performance on older systems, particularly devices running Windows 10 and older macOS versions. Due to limited access to such hardware, broader coverage will rely on community testing and feedback. The primary goals of this PR have been achieved, with several additional issues resolved along the way, resulting in improved stability and performance. Based on current results, the codebase is in a suitable state for merging. With this work complete, development can now proceed to the next phase: restructuring the data import pipeline and integrating B-Risk. Any further issues identified should be raised as tickets and addressed as part of upcoming feature development. |
Have applied hotfixes addressing issues outlined in previously rejected PR. #7
During follow-up work on previously identified issues, an additional problem was discovered: the memory trim method was being called from within the agent data runnable thread, despite only being safe to execute on the game thread and only triggered inside package versions not in editor mode. This has now been corrected.
Alongside this fix, further memory optimizations and general bug fixes have been applied. Based on current testing, this PR now meets the intended branch goals and is considered stable, provided the final validations pass.
Before merging, two final validation steps are required:
Due to hardware limitations, macOS testing has only been completed on a high-performance MacBook. Broader validation on older Apple hardware will require support from the community and other contributors.