Below is a concise, code‑verified summary of GraphBit’s memory efficiency techniques, with short excerpts and file paths.
1) Memory‑optimized executor profile
- Purpose: run in constrained environments with reduced footprint by lowering concurrency and disabling extras.
- Rust executor profile:
/// Create a workflow executor optimized for memory usage
pub fn new_memory_optimized() -> Self {
let concurrency_config = ConcurrencyConfig::memory_optimized();
let concurrency_manager = Arc::new(ConcurrencyManager::new(concurrency_config));
Self { /* smaller pre-allocs, conservative settings */ }
}
- Python binding (lower concurrency, disable metrics):
fn new_memory_optimized(..) -> PyResult<Self> {
let mut config = ExecutionConfig {
`mode: ExecutionMode::MemoryOptimized,`
`max_concurrency: Some(2), // Lower concurrency to save memory`
`enable_metrics: false, // Disable metrics to save memory`
`..Default::default()`
};
// ...
}
2) Memory‑lean concurrency configuration
- Purpose: cap simultaneous work per node type to control peak memory.
pub fn memory_optimized() -> Self {
let mut node_type_limits = HashMap::with_capacity(8);
node_type_limits.insert("agent".to_string(), 5);
node_type_limits.insert("transform".to_string(), 12);
// ...
Self { global_max_concurrency: 32, node_type_limits }
}
3) Benchmark memory measurement (validation)
- Purpose: track actual memory usage with tracemalloc + RSS deltas.
tracemalloc.start()
self.start_memory = self.process.memory_info().rss / 1024 / 1024
# ...
current_memory, peak_memory = tracemalloc.get_traced_memory()
memory_usage_mb = end_memory - self.start_memory
4) Pre‑allocation to avoid reallocs and fragmentation
- Purpose: reduce allocations and peak usage in hot structures.
Self {
node_map: HashMap::with_capacity(16),
nodes: HashMap::with_capacity(16),
edges: Vec::with_capacity(16),
// ...
}
5) Graph‑level caching (less repeated allocation/work)
- Purpose: cache dependency lookups to avoid rebuilding vectors repeatedly.
// Cached adjacency information for performance
if let Some(deps) = self.dependencies_cache.get(node_id) {
return deps.clone();
}
6) Provider‑level caching to avoid redundant setup
- Purpose: skip repeated model verification (keeps memory churn low).
// Fast path: check cache first to avoid repeated API calls
let verified = self.model_verified.read().await;
if *verified { return Ok(()); }
// ... set *verified = true after first check
7) Memory health checks in Node.js bindings
- Purpose: basic guardrails to surface low‑memory conditions.
let memory_healthy =
available_memory_mb.map_or(true, |mem| mem > 100); // At least 100MB
if !memory_healthy { warn!("Low available memory: {} MB", available); }
8) jemalloc on Unix (allocator choice)
- Purpose: improved allocation behavior and memory efficiency on Unix; disabled where problematic.
#[cfg(all(not(feature = "python"), unix))]
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;
Top comments (0)