Skip to content

[Bug]: Terminal entries grow unbounded causing memory leak #1648

@Fikri-20

Description

@Fikri-20

Describe the bug/problem

The TerminalController in lib/providers/terminal_providers.dart allows unbounded growth of terminal log entries, potentially causing memory issues during long-running sessions with frequent network requests and logging.

Steps to Reproduce the bug/problem

  1. Use API Dash extensively over a long period
  2. Make many API requests, especially streaming responses
  3. Each request adds multiple terminal entries (start, chunks, completion)
  4. Monitor memory usage over time
  5. Result: Memory consumption grows continuously without limit

Expected behavior

The terminal should maintain a reasonable maximum number of entries and automatically remove old entries when the limit is reached, preventing unbounded memory growth while still providing useful debugging history.

Root Cause

File: lib/providers/terminal_providers.dart, line 34-38

Current code:

String append(TerminalEntry entry) {
  final list = [entry, ...state.entries];
  state = TerminalState(entries: list);
  return entry.id;
}

Problem: The append method prepends new entries to the list but never removes old entries, allowing the list to grow indefinitely. For streaming responses, each chunk creates an update, and for long sessions, this can accumulate thousands of entries.

Impact Analysis

Memory Growth Example:

  • Each network request creates 1-3+ terminal entries
  • Streaming responses can create 10-100+ entries per request
  • A developer working for 4 hours with moderate API usage could accumulate 10,000+ entries
  • Each entry contains metadata, timestamps, and potentially large response bodies

Performance Impact:

  • Slower state updates as the list grows
  • Increased memory pressure
  • Potential UI lag when rendering the terminal

Proposed Solution

Implement a maximum entries limit with automatic cleanup:

class TerminalController extends StateNotifier<TerminalState> {
  TerminalController() : super(TerminalState(entries: <TerminalEntry>[]));

  static const _uuid = Uuid();
  static const int _maxEntries = 1000;  // Reasonable limit

  String append(TerminalEntry entry) {
    final list = [entry, ...state.entries];
    if (list.length > _maxEntries) {
      list.removeRange(_maxEntries, list.length);
    }
    state = TerminalState(entries: list);
    return entry.id;
  }

Benefits:

  • Prevents unbounded memory growth
  • Maintains 1000 entries of recent history (sufficient for debugging)
  • Automatic cleanup requires no user intervention
  • No breaking changes to existing functionality

Device Info

  • OS: All platforms (cross-platform issue)
  • Version: Not platform-specific
  • Environment: Production & Development

Impact

Severity: Medium - Performance and memory issue
Frequency: Occurs during extended usage sessions
User Impact: Degraded performance over time, potential memory exhaustion in resource-constrained environments

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    In progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions