Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 16, 2025

RAM grows continuously during automation demo due to allocations in the visualization update loop (runs at ~100Hz) and demo loop state retrievals.

Changes

Visualization loop (primary fix)

  • Reuse single List<> instance instead of allocating new one every 10ms (~100/sec reduction)
  • Replace LINQ Where() with indexed for-loop to eliminate enumerator allocations
  • Fix bug: change early return to continue to process all manipulators
  • Throttle position requests: Reduce network polling from 100 Hz to 10 Hz to minimize immutable state object creation
  • Cache positions: Store last known position per manipulator to avoid redundant network calls

Demo loop

  • Cache coordinates at loop start; reduce GetState<SceneState> calls from 5 to 1 per iteration (80% reduction)
  • Extract CheckDemoStillRunning() helper to deduplicate state checks

State change handler

  • Replace foreach with for-loop in OnSceneStateChanged()

Position request throttling

  • Implement 100ms throttle window per manipulator (10 Hz vs 100 Hz)
  • Cache last known positions and timestamps
  • Reduces network requests by 90% and immutable state allocations by 90%
  • Clear caches on disconnect to avoid stale data

Example

Before:

private async Task UpdateVisualizationProbePosition(SceneState sceneState)
{
    List<(...)> requests = new();  // New allocation every 10ms
    foreach (var manipulatorState in sceneState.Manipulators.Where(...))  // LINQ allocations
    {
        if (error) return;  // Bug: exits early, skips other manipulators
        
        // Network request every 10ms per manipulator
        var positionResponse = await GetPosition(manipulatorState.Id);
        
        // Creates new immutable state object every 10ms
        _storeService.Store.Dispatch(...);
    }
}

After:

private async Task UpdateVisualizationProbePosition(SceneState sceneState)
{
    _visualizationUpdateRequests.Clear();  // Reuse existing list
    var currentTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    
    foreach (var manipulatorState in sceneState.Manipulators)  // No LINQ
    {
        if (error) continue;  // Process all manipulators
        
        // Throttle to 10 Hz - use cached position 90% of the time
        if (ShouldRequestPosition(manipulatorState.Id, currentTime))
        {
            currentPosition = await GetPosition(manipulatorState.Id);
            CachePosition(manipulatorState.Id, currentPosition, currentTime);
        }
        else
        {
            currentPosition = GetCachedPosition(manipulatorState.Id);
        }
        
        // Dispatch only when position actually changed (90% reduction)
    }
}
Original prompt

This section details on the original issue you should resolve

<issue_title>Memory leak during automation demo</issue_title>
<issue_description>RAM usage grows continuously during the automation demo. Check for memory leaks in ephys link service for leaks in the demo loop implementation and also how manipulators update and check their position. The demo is also part of the manipulator inspector view model.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits November 16, 2025 20:17
Co-authored-by: kjy5 <82800265+kjy5@users.noreply.github.com>
Co-authored-by: kjy5 <82800265+kjy5@users.noreply.github.com>
Co-authored-by: kjy5 <82800265+kjy5@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix memory leak during automation demo Fix memory leak in automation demo visualization loop Nov 16, 2025
Copilot AI requested a review from kjy5 November 16, 2025 20:22
@kjy5 kjy5 marked this pull request as ready for review November 16, 2025 20:23
@kjy5
Copy link
Member

kjy5 commented Nov 16, 2025

@copilot The changes helped, but there is still a leak. Particularly when connected to manipulators. The memory grows more slowly now, but it still grows and needs garbage collection. I think this is due to the immutable state change system that the state system uses. Frequent updates to that are harsh. What suggestions are there to fix this?

Copy link
Contributor Author

Copilot AI commented Nov 16, 2025

@copilot The changes helped, but there is still a leak. Particularly when connected to manipulators. The memory grows more slowly now, but it still grows and needs garbage collection. I think this is ...

I've addressed the remaining leak caused by the immutable state system. The issue was that we were polling manipulator positions every 10ms (~100 Hz), which created:

  1. Network requests at 100 Hz generating async state machines
  2. State dispatches at 100 Hz creating new immutable state objects

Solution implemented (commit 8340aa5):

  • Added position request throttling (100ms interval = 10 Hz instead of 100 Hz)
  • Cached last known positions per manipulator
  • Reuse cached positions between throttle windows
  • Clear caches on disconnect to avoid stale data

This reduces network requests and state allocations by 90%, from ~100/sec to ~10/sec. The visualization loop still runs at 100 Hz for smooth UI updates, but only fetches new positions and dispatches state updates at 10 Hz.

The GC should now be able to keep up with the reduced allocation rate.

@kjy5 kjy5 force-pushed the copilot/fix-memory-leak-demo branch from 2c963d1 to 16097ad Compare November 16, 2025 23:32
@kjy5
Copy link
Member

kjy5 commented Nov 21, 2025

Superceded by #849

@kjy5 kjy5 closed this Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak during automation demo

2 participants