Memory Management
This document describes memory management patterns, optimization strategies, and cleanup procedures implemented in src/runtime/memory/MemoryManager.ts.
Overview
The Memory object in Screeps persists between ticks and can grow unbounded if not properly managed. The MemoryManager handles hygiene by pruning stale entries and maintaining aggregate statistics.
Memory Structure
Top-Level Memory Schema
1 | interface Memory { |
Creep Memory Schema
1 | interface CreepMemory { |
Role Counts Schema
1 | interface RoleCounts { |
Memory Hygiene Operations
Pruning Stale Creep Memories
Trigger: Every tick via Kernel.run()
Method: MemoryManager.pruneMissingCreeps()
Algorithm:
1 | 1. Iterate all keys in Memory.creeps |
Example Log:
1 | Removed 2 stale creep memories: harvester-12345-789, upgrader-12350-123 |
Purpose:
- Prevents unbounded memory growth
- Reclaims memory from dead creeps
- Keeps memory access performant
Memory Savings:
- ~50-100 bytes per pruned creep
- Prevents multi-KB accumulation over hundreds of ticks
Updating Role Bookkeeping
Trigger: Every tick via Kernel.run()
Method: MemoryManager.updateRoleBookkeeping()
Algorithm:
1 | 1. Initialize empty role count map |
Example Result:
1 | { |
Purpose:
- Provides aggregate statistics for spawn logic
- Enables quick population queries without iteration
- Caches derived data for efficiency
CPU Cost: ~0.05-0.1 CPU per tick
Memory Access Patterns
Read Patterns
Per-Tick Reads (executed every tick):
Memory.creeps[name]: Individual creep memory (per creep)Memory.roles: Role population counts (once per tick)Memory.respawn: Respawn state (once per tick)Memory.systemReport: Last evaluation (once per tick)
Cost: ~0.1 CPU total per tick
Optimization: Direct property access is faster than Object.keys() iteration
Write Patterns
Per-Tick Writes:
Memory.creeps[name].task: Task state updates (per creep)Memory.roles: Role counts (once per tick)Memory.respawn: Respawn state changes (when needed)Memory.systemReport: Evaluation results (when needed)
Cost: ~0.05-0.1 CPU total per tick
Optimization: Batch writes minimize serialization overhead
Memory Size Limits
Practical Limits
Screeps has a soft limit of 2MB per Memory object, but performance degrades significantly before that:
Performance Tiers:
- <100 KB: Excellent (no noticeable impact)
- 100-500 KB: Good (minor CPU overhead)
- 500 KB - 1 MB: Degraded (noticeable CPU cost)
- 1+ MB: Poor (significant CPU cost, risk of limit)
Current Memory Usage (Typical)
Baseline (3 creeps, RCL 1):
1 | Memory.creeps: ~300 bytes (100 bytes × 3 creeps) |
Scaled (50 creeps, RCL 6):
1 | Memory.creeps: ~5 KB (100 bytes × 50 creeps) |
Growth Rate: ~100 bytes per creep (baseline memory structure)
Memory Cleanup Strategies
Automatic Cleanup
Implemented Strategies:
Creep Memory Pruning (Every tick)
- Removes memory for dead creeps
- Prevents unbounded growth
- Zero manual intervention required
Role Count Updates (Every tick)
- Overwrites previous counts
- No historical data accumulation
- Self-maintaining
Manual Cleanup (If Needed)
Orphaned Respawn State:
1 | // Clear respawn state manually in console |
Old System Reports:
1 | // Clear old evaluation results |
Complete Memory Reset (Nuclear option):
1 | // WARNING: Deletes ALL memory |
Selective Cleanup
Remove Specific Role Memories:
1 | // Remove all harvester memories |
Memory Corruption Recovery
Detection
Symptoms:
- Creeps behave incorrectly
- Role counts incorrect
- System evaluation failures
- Error logs about missing memory fields
Diagnostic Queries (in console):
1 | // Check for creeps with missing role |
Recovery Procedures
Level 1: Automatic Recovery (Handled by runtime)
- Creep version mismatches → Reset to defaults
- Missing task fields → Reset to role default
- No manual intervention needed
Level 2: Guided Recovery
1 | // Force memory refresh (in console) |
Level 3: Full Reset (Last resort)
1 | // Complete memory wipe and rebuild (in console) |
Prevention Strategies
Validate Before Write
- Always check memory field types
- Use TypeScript for compile-time checks
- Validate in tests
Defensive Reads
- Check for undefined/null before using
- Provide fallback defaults
- Example:
const role = creep.memory.role || 'harvester'
Version Migration
- Increment role versions when changing memory structure
- Detect old versions and reset safely
- Prevents incompatible memory layouts
Memory Optimization Techniques
1. Avoid Storing Redundant Data
Bad:
1 | creep.memory.sourceId = source.id; |
Good:
1 | creep.memory.sourceId = source.id; // Only store ID, derive rest |
2. Use Short Property Names
Impact: ~30% memory savings on deeply nested objects
Bad:
1 | { |
Good:
1 | { |
3. Avoid Storing Entire Objects
Bad:
1 | creep.memory.target = targetStructure; // Stores entire object! |
Good:
1 | creep.memory.targetId = targetStructure.id; // Store only ID |
4. Use Bitflags for Boolean States
For advanced users: Multiple booleans can be stored as single number
Example:
1 | // Instead of: |
Savings: ~75% memory for boolean flags
Memory Persistence Patterns
Transient State (DO NOT PERSIST)
Examples:
- Pathfinding cache (regenerated each tick)
- Target distance calculations
- Temporary variables in task logic
Guideline: If it can be recalculated cheaply, don’t store it.
Persistent State (OK TO PERSIST)
Examples:
- Role assignment (changes rarely)
- Current task state (changes per task cycle)
- Role version (changes on code updates)
- Assigned resource IDs (stable across ticks)
Guideline: If recalculation is expensive or state must survive tick boundary, persist it.
Cached State (CONDITIONAL PERSISTENCE)
Examples:
- Source assignments (recalculate every N ticks)
- Room statistics (refresh every 10-100 ticks)
- Pathfinding results (cache for 5-50 ticks)
Guideline: Store with TTL, refresh when expired.
Memory Usage Monitoring
Manual Inspection
Check Memory Size (in console):
1 | // Approximate memory size in bytes |
Per-Creep Memory Size:
1 | // Average memory per creep |
Automated Monitoring
Track in System Evaluation:
1 | // Add to SystemEvaluator.evaluate() |
Best Practices Summary
Based on the ScreepsPlus Memory Wiki:
DO:
- ✓ Prune dead creep and flag memories every tick
- ✓ Store only essential state in memory (IDs, not objects)
- ✓ Use IDs instead of object references
- ✓ Validate memory structure before use
- ✓ Implement version migrations for schema changes
- ✓ Use
GlobalCachefor volatile, non-persistent data - ✓ Serialize paths before storing in creep memory
- ✓ Clean up flag memories when flags are removed
DON’T:
- ✗ Store entire game objects in memory
- ✗ Accumulate historical data without limits
- ✗ Store redundant/derivable information
- ✗ Use long property names unnecessarily
- ✗ Persist transient state
- ✗ Store RoomPosition arrays directly (use serialized format)
- ✗ Store function references or class instances
MONITOR:
- ⚠ Total memory size (keep <100 KB for good performance)
- ⚠ Memory growth rate (should be stable)
- ⚠ Orphaned memory entries (should be zero)
- ⚠ CPU cost of memory operations (should be <0.2 CPU/tick)
Advanced Memory Patterns
Global Heap Caching
Use GlobalCache for volatile data that doesn’t need to persist across code reloads:
1 | import { globalCache } from "@runtime/memory"; |
Benefits:
- No JSON serialization overhead
- Can store complex objects, functions, references
- No impact on Memory size limits
Path Serialization
Use path serialization to reduce creep memory footprint:
1 | import { serializePositions, deserializePath, getRemainingPath } from "@runtime/pathfinding"; |
Memory savings: ~85% reduction (40 bytes per position → 1 byte per step)
Flag Memory Cleanup
The garbage collector automatically cleans orphaned flag memories:
1 | // Cleanup happens automatically via MemoryGarbageCollector |
Memory Segments
For large data sets exceeding 2MB limit, consider RawMemory segments:
- Up to 100 segments × 100KB = 10MB total
- Requires manual serialization/deserialization
- Only 10 segments can be active per tick
1 | // Activate segments (up to 10 per tick) |
Related Documentation
- Creep Roles - Memory structure for each role
- Safe Refactoring - How to migrate memory schemas safely
- Performance Monitoring - CPU impact of memory operations
- Respawn Procedures - Memory state during respawn