Memory Management in Long-Running Processes: Laravel Guide
Master memory management for Laravel queue workers and CLI tasks. Learn to identify leaks, set memory thresholds, and keep your production processes stable.
Previously in this course, we discussed profiling PHP execution to identify bottlenecks. Today, we shift our focus from execution speed to memory stability. When running Laravel queue workers or long-lived CLI tasks, memory leaks can silently accumulate, eventually leading to OOM (Out of Memory) crashes that destabilize your production environment.
Understanding Memory in CLI Processes
Unlike a standard web request that spins up, executes, and terminates in milliseconds, a long-running CLI process stays alive for hours or days. In this lifecycle, any object referenced in a static variable, a long-lived service container binding, or a global array will remain in memory for the duration of the process.
If your code creates objects inside a loop without clearing them—or if you're using libraries that cache metadata in static properties—your memory footprint will grow monotonically. This is the hallmark of a memory leak in PHP.
Identifying Memory Leaks
Before you add restart thresholds, you must identify the source. If your worker's memory consumption follows a linear "sawtooth" pattern that never returns to a baseline, you have a leak.
- Monitor with
memory_get_usage(): Inject this into your job'shandle()method during development. - Use
htoportop: Monitor the Resident Set Size (RSS) of your specific worker process. - Check for Circular References: As discussed in Laravel Octane Memory Management: Solving Circular Reference Leaks, PHP's garbage collector sometimes struggles with complex object graphs.
Configuring Worker Restart Thresholds
Laravel provides a built-in safety net for this exact problem. Instead of trying to achieve "perfect" memory management, we use a "restart on limit" strategy.
When running your queue workers, you should always define a memory limit. This tells the worker: "If you exceed this amount of RAM, finish your current job, then kill yourself so the supervisor can spawn a fresh, clean process."
You can configure this globally or per-worker:
Bash# Start a worker that restarts if it hits 128MB php artisan queue:work --memory=128
If you are using Laravel Horizon for your queue management, define this in your config/horizon.php file under the environments section:
PHP'environments' => [ 'production' => [ 'supervisor-1' => [ 'connection' => 'redis', 'queue' => ['default', 'imports'], 'balance' => 'auto', 'memory' => 128, #6A9955">// The magic threshold ], ], ],
Worked Example: The "Leak" Pattern
Consider an importer job that processes thousands of rows. If you aren't careful, you might be keeping the entire collection of processed records in a static property.
PHPclass ProcessLargeImport implements ShouldQueue { #6A9955">// BAD: Static property grows indefinitely public static $processedItems = []; public function handle() { $item = $this->repository->getNext(); #6A9955">// This will eventually crash the worker self::$processedItems[] = $item; $item->process(); } }
To fix this, you must ensure that your memory is cleared after every job. If you find yourself needing to cache data across jobs, use Redis or a cache store rather than memory-resident arrays. For high-throughput scenarios, look into Laravel Octane Memory Management: Implementing Custom Object Pooling to recycle objects instead of leaking them.
Hands-on Exercise
- Create a test command that simulates a memory leak by appending strings to a static array in a loop.
- Run the command and observe the memory usage using
memory_get_usage(true). - Implement a check inside the loop: if
memory_get_usage() > 1024 * 1024 * 10(10MB), throw an exception or exit. - Restart the process and verify that the memory resets to the baseline.
Common Pitfalls
- Setting the limit too low: If your jobs process large files, they might hit the limit before completing a single job. Ensure your
--memorylimit is at least 2-3x the size of your largest expected peak memory usage. - Ignoring
php.ini: CLI memory limits are distinct from web memory limits. Check yourphp --inioutput to ensure your CLI environment isn't restricted by amemory_limitthat is lower than your worker threshold. - Static Properties: Always audit your code for
public staticproperties. They are the most common source of leaks in long-running Laravel processes.
Recap
Memory management in long-running processes is about containment. By monitoring your memory growth, using tools like Horizon to set strict memory thresholds, and avoiding the usage of static properties for state, you ensure your background workers remain stable under heavy load.
Up next: We will discuss how to write effective tests for your domain-driven components in Testing DDD Components.
Work with me

Laravel REST API Development
Clean, secure, well-documented Laravel REST APIs — the backend engine for your app, mobile client, or SaaS. Built by an API specialist.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app — built with FilamentPHP so you can manage everything without touching the database.