Memory & Buffer Management
Relevant source files
The following files were used as context for generating this wiki page:
Memory and Buffer Management in Keynobi is designed around the principle of bounded collections to ensure the application remains performant during long development sessions. The system employs ring buffers for high-frequency data (like Logcat), batched emission to the frontend to prevent UI thread flooding, and automated disk rotation for persistent log storage.
The architecture prioritizes flat memory usage by storing large logs in the Rust backend and only serializing necessary portions to the frontend via virtualized lists. This approach prevents memory leaks and performance degradation when handling thousands of log entries or multiple Gradle build cycles.
Core Architectural Principles
The project enforces strict rules regarding how data is stored and transferred between the Rust backend and the SolidJS frontend.
- Bounded Collections: Every in-memory collection that grows must have an explicit cap to prevent unbounded growth. Sources: AGENTS.md:31
- Ring Buffers: High-volume data like Logcat entries are stored in 50,000-entry ring buffers in Rust and are never serialized to disk in their entirety. Sources: README.md:209-211
- Batching: Logcat and Build entries are batched (e.g., 100ms or 50ms intervals) before being emitted to the frontend to avoid overwhelming the reactive state. Sources: README.md:212-214, src/stores/build.store.ts:109-113
- Virtualization: Large datasets are rendered using virtualized lists so that only visible rows exist in the DOM, maintaining UI responsiveness. Sources: CHANGELOG.md:46
Build Log & History Management
The Build system manages memory by splitting data between an active "Build Log" ring buffer and persistent "Build History" records.
In-Memory Buffers
Active build logs are maintained in a thread-safe BuildLog (a VecDeque wrapped in a Mutex). This buffer is capped at 5,000 lines to ensure the backend does not consume excessive memory during extremely verbose Gradle tasks. On the frontend, the buildLogStore maintains a separate 10,000-line cap.
The diagram shows the flow of build output from the process to the capped in-memory buffers in both backend and frontend. Sources: src-tauri/src/services/build_runner.rs:95-103, src/stores/build.store.ts:51
Persistent Storage and Rotation
When a build finalizes, the raw log is converted to JSON Lines (.jsonl) and saved to disk. To prevent the log folder from growing indefinitely, a rotation service triggers on every build completion.
| Parameter | Default Value | Description |
|---|---|---|
MAX_HISTORY | 10 entries | In-memory records of past builds. |
MAX_PERSISTED_HISTORY | 20 entries | Maximum records saved in the history JSON file. |
buildLogRetentionDays | User Config (1-365) | Days to keep .jsonl logs before deletion. |
buildLogMaxFolderMb | User Config (10-2048) | Size cap for the log folder before oldest logs are purged. |
Sources: src-tauri/src/services/build_runner.rs:13-17, src/components/settings/SettingsPanel.tsx:325-345
Logcat Pipeline & Ring Buffer
Logcat management is the most memory-intensive part of the application. The system uses a specialized pipeline to enrich raw lines before storing them.
Pipeline Context and Separators
The PipelineContext manages state during a logcat session, including mappings of PIDs to package names. This avoids repetitive lookups and allows the pipeline to generate synthetic "Separator" entries (e.g., process died/restarted) without re-parsing the entire buffer. Sources: src-tauri/src/services/log_pipeline.rs:25-35
Monitoring and Warnings
The application monitors the Logcat buffer's health. If the buffer usage exceeds 80%, a warning is displayed in the Health Center to notify the user that oldest entries may be lost. Sources: src/components/health/HealthPanel.tsx:505-520
This sequence illustrates the path of logcat data from the device to the UI, emphasizing the batching and capping mechanisms. Sources: README.md:209-214
System Health & Resource Monitoring
The application provides real-time visibility into its own resource consumption and the memory usage of the Android apps being inspected.
App Memory Tracking
Keynobi tracks the memory footprint of the targeted Android package using dumpsys meminfo. It extracts specific metrics to help developers identify leaks:
- Java Heap PSS/RSS
- Native Heap PSS/RSS
- Graphics PSS/RSS
- Total PSS
Sources: src-tauri/src/services/device_inspector.rs:27-37
Companion App Monitoring
The status bar displays the current memory usage (RSS) of the Keynobi process itself and the total size of the log folder.
The diagram shows how internal system metrics are gathered and visually communicated through the status bar. Sources: src/components/layout/StatusBar.tsx:115-135, src/components/layout/StatusBar.tsx:142-156
Summary
Memory and Buffer management in Keynobi is a multi-layered system designed for stability. By enforcing a 50,000-line cap on Logcat, a 5,000-line cap on active build logs, and providing user-configurable rotation for persistent files, the application ensures that neither the Rust backend nor the WKWebView frontend exceeds reasonable resource limits. The use of batched IPC and virtualized lists further protects UI performance from high-frequency data streams.
Sources: README.md:209-220, src-tauri/src/services/build_runner.rs:80-90