Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 36 of the Advanced Laravel: Architecture, Scaling & Performance course
LaravelJune 28, 20264 min read

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.

LaravelPHPPerformanceMemoryCLIQueuesbackend

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.

  1. Monitor with memory_get_usage(): Inject this into your job's handle() method during development.
  2. Use htop or top: Monitor the Resident Set Size (RSS) of your specific worker process.
  3. 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.

PHP
class 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

  1. Create a test command that simulates a memory leak by appending strings to a static array in a loop.
  2. Run the command and observe the memory usage using memory_get_usage(true).
  3. Implement a check inside the loop: if memory_get_usage() > 1024 * 1024 * 10 (10MB), throw an exception or exit.
  4. 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 --memory limit 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 your php --ini output to ensure your CLI environment isn't restricted by a memory_limit that is lower than your worker threshold.
  • Static Properties: Always audit your code for public static properties. 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.

Previous lessonProfiling PHP ExecutionNext lesson Testing DDD Components
Back to Blog

Similar Posts

LaravelJune 26, 20264 min read

Asynchronous Processing with Queues in Laravel

Improve application performance by offloading heavy tasks to queues. Learn how to configure drivers, create job classes, and dispatch background jobs.

Read more
LaravelJune 28, 20263 min read

Handling Large File Uploads: Streaming to S3 & Async Processing

Master scalable file uploads in Laravel. Learn to stream directly to S3 and process heavy files asynchronously to keep your application fast and memory-efficient.

Part of the course

Advanced Laravel: Architecture, Scaling & Performance

advanced · Lesson 36 of 57

  1. 1

    Transitioning from MVC to DDD

    3 min
  2. 2

    Defining Bounded Contexts

    3 min
  3. 3

    Implementing Action Classes

    3 min
Read more
LaravelJune 28, 20263 min read

Profiling PHP Execution: Mastering Performance Analysis in Laravel

Stop guessing why your application is slow. Learn to use Xdebug and Blackfire to profile PHP execution, identify memory bottlenecks, and analyze call traces.

Read more
4

Utilizing Data Transfer Objects (DTOs)

3 min
  • 5

    Service Layer Pattern

    4 min
  • 6

    Modular Monolith Structure

    3 min
  • 7

    Querying with Strict Eloquent

    4 min
  • 8

    Advanced Subqueries and Joins

    4 min
  • 9

    Raw Expressions for Performance

    4 min
  • 10

    Advanced Indexing Strategies

    4 min
  • 11

    Database Partitioning Techniques

    4 min
  • 12

    Read/Write Database Splitting

    4 min
  • 13

    Handling Multi-Database Connections

    3 min
  • 14

    Eloquent Caching Strategies

    3 min
  • 15

    Queue Worker Prioritization

    4 min
  • 16

    Unique Job Patterns

    4 min
  • 17

    Rate Limiting Background Jobs

    3 min
  • 18

    Event-Driven Architecture

    4 min
  • 19

    Integrating External Message Brokers

    4 min
  • 20

    Distributed Transactions and Sagas

    3 min
  • 21

    Eventual Consistency Patterns

    4 min
  • 22

    Multi-Layered Caching Strategy

    4 min
  • 23

    Cache Tagging and Invalidation

    4 min
  • 24

    Session Persistence in Clusters

    4 min
  • 25

    High-Availability Infrastructure

    4 min
  • 26

    Zero-Downtime Deployment Pipelines

    4 min
  • 27

    Advanced OAuth2 Implementation

    3 min
  • 28

    JWT and Stateless Security

    4 min
  • 29

    Multi-Tenant Security Isolation

    3 min
  • 30

    Defense Against SSRF

    3 min
  • 31

    Mass Assignment Hardening

    4 min
  • 32

    Automated Security Testing

    3 min
  • 33

    Custom Telemetry Design

    3 min
  • 34

    Distributed Tracing

    4 min
  • 35

    Profiling PHP Execution

    3 min
  • 36

    Memory Management in Long-Running Processes

    4 min
  • 37

    Testing DDD Components

    3 min
  • 38

    Contract Testing

    3 min
  • 39

    Handling Large File Uploads

    3 min
  • 40

    Optimizing Asset Pipelines

    4 min
  • 41

    Database Query Caching Layers

    3 min
  • 42

    Advanced Eloquent Scopes

    4 min
  • 43

    Distributed Locks

    3 min
  • 44

    API Versioning Strategies

    4 min
  • 45

    Database Migration Strategies

    4 min
  • 46

    Handling Webhooks Securely

    3 min
  • 47

    Advanced Logging Patterns

    3 min
  • 48

    Database Indexing for Joins

    4 min
  • 49

    Graceful Degradation

    3 min
  • 50

    Custom Middleware Development

    Coming soon
  • 51

    Database Connection Pooling

    Coming soon
  • 52

    Handling Large Data Exports

    Coming soon
  • 53

    Security Header Configuration

    Coming soon
  • 54

    Database Sharding Concepts

    Coming soon
  • 55

    Real-time Data Synchronization

    Coming soon
  • 56

    Database Deadlock Prevention

    Coming soon
  • 57

    Managing Third-Party API Integrations

    Coming soon
  • View full course