# LiveComponents Memory Management ## Current Architecture (✅ Already Good) ### No Instance Caching - **ComponentRegistry** creates fresh instances on each `resolve()` - No memory leaks from accumulated component instances - Components are garbage-collected after request ### TTL-Based Rendering Cache - **ComponentCacheManager** caches rendered HTML only - Automatic expiry via `Cacheable::getCacheTTL()` - Tag-based invalidation for related components - Delegates to Framework Cache (FileCache, ApcuCache, Redis) ### Framework Cache Handles Memory - FileCache: Disk-based, no memory issues - ApcuCache: APCu's memory management - Redis: Redis memory eviction policies - All support TTL and automatic cleanup ## Best Practices ### Component Design **✅ DO:** ```php final readonly class UserCardComponent implements LiveComponentContract { public function __construct( private ComponentId $id, private UserId $userId // ✅ Small Value Object ) {} public function getRenderData(): ComponentRenderData { // ✅ Load data on-demand $user = $this->userRepository->find($this->userId); return new ComponentRenderData( templatePath: 'user-card', data: ['user' => $user->toArray()] ); } } ``` **❌ DON'T:** ```php final readonly class BadComponent implements LiveComponentContract { public function __construct( private ComponentId $id, private array $allUsers // ❌ Large dataset in constructor! ) {} } ``` ### Caching Strategy **Cache Expensive Renders:** ```php final readonly class StatsComponent implements LiveComponentContract, Cacheable { public function shouldCache(): bool { return true; // ✅ Expensive calculation } public function getCacheTTL(): Duration { return Duration::fromMinutes(5); // ✅ Reasonable TTL } public function getCacheKey(): string { return "stats:{$this->dateRange->format()}"; // ✅ Vary by parameters } } ``` **Don't Cache Simple Renders:** ```php final readonly class ButtonComponent implements LiveComponentContract { // ❌ Don't implement Cacheable for simple components // Caching overhead > render cost } ``` ### Memory Monitoring **Per-Request Component Limits:** ```php // Future Enhancement: Request-level tracking final readonly class ComponentRequestTracker { private int $componentsCreated = 0; private const MAX_COMPONENTS_PER_REQUEST = 100; public function track(ComponentId $id): void { $this->componentsCreated++; if ($this->componentsCreated > self::MAX_COMPONENTS_PER_REQUEST) { throw new TooManyComponentsException( "Request exceeded component limit: {$this->componentsCreated}" ); } } } ``` ## Troubleshooting ### High Memory Usage **Symptoms:** - PHP memory limit errors - Slow response times - Cache growing too large **Diagnosis:** ```php // Check cache size $stats = $cacheManager->getStats($component); // Look at 'age_seconds' - old caches not expiring? // Monitor per-request component creation error_log("Components created this request: " . count($componentIds)); ``` **Solutions:** 1. **Reduce Cache TTL:** ```php public function getCacheTTL(): Duration { return Duration::fromMinutes(1); // Shorter TTL } ``` 2. **Implement Cache Tags:** ```php public function getCacheTags(): array { return ['user:' . $this->userId, 'dashboard']; } // Invalidate by tag when data changes $registry->invalidateCacheByTag('user:123'); ``` 3. **Use Conditional Caching:** ```php public function shouldCache(): bool { // Only cache for non-admin users return !$this->user->isAdmin(); } ``` 4. **Clear Old Caches:** ```bash # Cron job for cleanup */30 * * * * php console.php cache:clear --tags=livecomponents ``` ### Memory Leaks **Potential Issues:** - Event listeners not unsubscribed - Database connections in lifecycle hooks - Large closures in component state **Prevention:** ```php final readonly class SafeComponent implements LiveComponentContract, LifecycleAware { public function onMount(): void { // ✅ Subscribe to events $this->eventBus->subscribe('user.updated', $this->handleUserUpdate(...)); } public function onDestroy(): void { // ✅ ALWAYS unsubscribe $this->eventBus->unsubscribe('user.updated', $this->handleUserUpdate(...)); } } ``` ## Monitoring ### Recommended Metrics **Component Metrics:** - `livecomponent.created.count` - Components created per request - `livecomponent.render.duration_ms` - Render time distribution - `livecomponent.cache.hit_rate` - Cache effectiveness **Memory Metrics:** - `php.memory.usage_bytes` - Current memory usage - `php.memory.peak_bytes` - Peak memory per request - `cache.size_bytes` - Total cache size **Alert Thresholds:** - Memory usage > 80% of limit - Components per request > 50 - Cache hit rate < 50% - Render time > 200ms (p95) ## Production Configuration ```php // config/cache.php return [ 'livecomponents' => [ 'default_ttl' => 300, // 5 minutes 'max_cache_size' => '100MB', // Per-driver limit 'cleanup_interval' => 3600, // 1 hour 'enable_metrics' => true ] ]; ``` ## Future Enhancements ### Planned Improvements 1. **Request-Level Component Tracking** - Track component creation count - Enforce per-request limits - Alert on threshold violations 2. **Memory Usage Profiling** - Component memory footprint tracking - Automatic large component detection - Performance regression alerts 3. **Intelligent Cache Eviction** - LRU eviction when cache full - Prioritize by component usage frequency - Automatic TTL adjustment based on hit rate 4. **Component Lifecycle Monitoring** - Track component lifetime - Detect components never destroyed - Memory leak detection ## Summary ✅ **Current State:** Memory management is solid - No instance caches - TTL-based rendering cache - Framework cache handles underlying memory ✅ **No Immediate Action Required** - Architecture is already memory-safe - Follow best practices above - Implement monitoring for production ⚠️ **Future Work:** Request-level limits and enhanced monitoring (Phase 5 - Observability)