• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 9+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » Why the Linux OOM Killer Terminates Your Laravel Processes on AWS (And How to Prevent It)

Why the Linux OOM Killer Terminates Your Laravel Processes on AWS (And How to Prevent It)

Understanding the Linux OOM Killer

When a Linux system runs out of available memory, it invokes the Out-Of-Memory (OOM) Killer. This kernel process’s sole purpose is to reclaim memory by terminating one or more processes. It’s a last resort to prevent a system-wide crash. The OOM Killer uses a heuristic scoring system to decide which process is the “best” candidate for termination. This score is influenced by factors like memory usage, process niceness, and how long the process has been running. Unfortunately, this can lead to unexpected termination of critical applications, including your Laravel processes running on AWS EC2 instances.

Identifying OOM Killer Activity

The first step in diagnosing OOM killer events is to check system logs. The kernel logs messages when it invokes the OOM Killer. On most modern Linux distributions, these messages are sent to `syslog` and can be found in files like `/var/log/messages`, `/var/log/syslog`, or viewed via `journalctl`.

To specifically search for OOM killer messages, you can use `grep` or `journalctl`:

sudo grep -i "killed process" /var/log/messages
sudo journalctl -k | grep -i "oom-killer"

A typical OOM killer log entry will look something like this:

[timestamp] Out of memory: Kill process [PID] ([process_name]) score [score] or sacrifice child

The `[PID]` and `[process_name]` are crucial for identifying which of your Laravel-related processes (e.g., PHP-FPM, Artisan queue workers, web server) was terminated. The `score` indicates how likely the OOM killer deemed that process to be a suitable candidate for termination.

Laravel Processes and Memory Consumption

Laravel applications, especially those with heavy traffic, complex queries, or extensive use of caching and background jobs, can be memory-intensive. Common culprits for high memory usage in a Laravel context include:

  • PHP-FPM Workers: Each worker process handles incoming HTTP requests. If configured with too many workers or if individual requests consume significant memory (e.g., large data processing, complex view rendering), the total memory footprint can escalate rapidly.
  • Artisan Queue Workers: Long-running queue workers that process many jobs without proper memory management can accumulate memory over time. This is particularly true for jobs that load large datasets or perform complex operations.
  • Database Connections and Caching: Inefficient database queries, large result sets being loaded into memory, or aggressive in-memory caching strategies can contribute to memory pressure.
  • Third-Party Packages: Some packages might have memory leaks or be inherently memory-hungry.

Strategies to Prevent OOM Termination

1. Optimize PHP-FPM Configuration

PHP-FPM’s process management is a primary area for tuning. The `pm.max_children` setting directly controls the maximum number of child processes that can be spawned. Setting this too high is a common cause of OOM issues.

You can calculate a reasonable `pm.max_children` based on your available RAM and the average memory usage of a single PHP-FPM process. First, determine the average memory usage of a PHP-FPM process:

ps aux | grep "php-fpm" | grep -v grep | awk '{sum+=$6} END {print sum / (1024*1024) " MB"}'

Let’s say your EC2 instance has 8GB of RAM (approx. 8388608 KB) and a single PHP-FPM process typically uses 50MB (approx. 52428 KB). You also need to reserve memory for the OS, Nginx, database, and other services. A conservative approach might be to reserve 2GB for the OS and other services. This leaves 6GB (approx. 6291456 KB) for PHP-FPM.

pm.max_children = (Available RAM for PHP-FPM) / (Average PHP-FPM process memory usage)
pm.max_children = 6291456 KB / 52428 KB ≈ 120

You would then adjust your PHP-FPM pool configuration (e.g., `/etc/php/8.1/fpm/pool.d/www.conf` or similar) accordingly:

; pm.max_children = 50 ; Default or previous value
pm.max_children = 120 ; New calculated value

; Other relevant settings to consider:
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500 ; Restart processes after this many requests to clear memory

After making changes, restart PHP-FPM:

sudo systemctl restart php8.1-fpm

2. Manage Artisan Queue Workers

Queue workers are often long-running processes. If they don’t release memory effectively, they can become prime targets for the OOM killer. Consider these strategies:

  • Limit Concurrency: If you’re running multiple queue workers, ensure the total number of workers multiplied by their average memory usage doesn’t exceed available memory.
  • Restart Workers Regularly: Use a process manager like `supervisor` to automatically restart queue workers after a certain number of jobs or a specific uptime. This helps to clear any accumulated memory.
  • Monitor Job Memory Usage: Profile your jobs to identify any that consume excessive memory. Optimize these jobs by processing data in chunks, releasing large objects when no longer needed, and avoiding loading entire datasets into memory.
  • Use `queue:restart` with caution: While `php artisan queue:restart` can be useful, it restarts all workers. If you have many workers, this can cause a temporary spike in resource usage.

Example `supervisor` configuration to restart a worker after every 1000 jobs:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/artisan queue:work --queue=default,high --sleep=3 --tries=3
autostart=true
autorestart=true
user=www-data
numprocs=4 ; Number of concurrent workers
redirect_stderr=true
stdout_logfile=/var/log/supervisor/laravel-worker.log
; Restart after 1000 jobs
numprocs_start=1000

After modifying supervisor configuration, reload and update:

sudo supervisorctl reread
sudo supervisorctl update

3. Tune MySQL and Database Interactions

Database operations can indirectly lead to high memory usage. For instance, fetching a large number of records into a Laravel collection can consume significant RAM. Ensure your queries are optimized and only fetch the necessary data.

Consider using Eager Loading to reduce the number of queries, but be mindful of the total data fetched. For very large datasets, use chunking:

<?php

use App\Models\User;

User::chunk(200, function ($users) {
    foreach ($users as $user) {
        // Process each user...
        // This avoids loading all users into memory at once.
    }
});
?>

Also, review your MySQL server’s memory configuration. While the MySQL server itself might not be the direct OOM victim, its memory usage contributes to the overall system load. Ensure `innodb_buffer_pool_size` and other memory-related settings are appropriately configured for your instance size.

4. Adjust OOM Killer Score (Use with Extreme Caution)

Linux allows you to influence the OOM killer’s decision-making by adjusting the `oom_score_adj` value for a process. This value ranges from -1000 (never kill) to 1000 (always kill). A higher score makes a process more likely to be killed.

You can set this value for a running process:

echo -1000 | sudo tee /proc/[PID]/oom_score_adj

To prevent a process from being killed by the OOM killer, you would set its `oom_score_adj` to -1000. However, this is generally a bad idea for critical system processes or applications that might have memory leaks. If you prevent a process from being killed, and it continues to consume memory, the OOM killer will be forced to kill other, potentially more critical, processes, or the system may become unstable.

A more nuanced approach is to slightly increase the `oom_score_adj` for less critical background processes, making them more likely to be killed before your web server or database. Conversely, you might slightly decrease it for essential worker processes if you’ve exhausted other optimization options, but this should be a last resort.

To make this persistent across reboots, you would typically use systemd unit files or init scripts. For example, in a systemd service file for your Laravel application:

[Service]
# ... other service configurations
ExecStart=/usr/bin/php /var/www/html/artisan queue:work ...
OOMScoreAdjust=-500 ; Make this process more likely to be killed if needed
# Or to make it less likely (use with extreme caution):
# OOMScoreAdjust=-1000

5. Monitor System Memory Usage

Proactive monitoring is key. Use tools like CloudWatch (on AWS), Prometheus with Node Exporter, or `htop` to keep an eye on your instance’s memory utilization. Set up alerts for high memory usage thresholds (e.g., 80-90%) so you can investigate before the OOM killer is invoked.

AWS CloudWatch metrics for EC2 instances include `CPUUtilization`, `NetworkIn`, `NetworkOut`, and `DiskReadOps`, `DiskWriteOps`. For memory, you’ll typically need to install the CloudWatch agent to send custom metrics like `mem_used_percent`.

# Example of installing CloudWatch agent (Ubuntu/Debian)
wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb
sudo dpkg -i amazon-cloudwatch-agent.deb
# Configure the agent with a JSON configuration file that includes memory metrics.
# Then start the agent:
sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/bin/config.json -s

Setting up an alarm in CloudWatch for `mem_used_percent` exceeding a certain threshold will notify you of potential issues.

6. Right-Size Your EC2 Instances

Ultimately, if your application consistently pushes the limits of your current instance size, the most robust solution is to scale up. Analyze your memory usage patterns over time. If you’re frequently hitting high memory utilization or experiencing OOM events despite optimization efforts, consider migrating to an EC2 instance type with more RAM. For memory-intensive workloads, instance families like `r` (e.g., `r5.large`, `r5.xlarge`) are designed for memory-optimized applications.

Primary Sidebar

A little about the Author

Having 9+ Years of Experience in Software Development.
Expertised in Php Development, WordPress Custom Theme Development (From scratch using underscores or Genesis Framework or using any blank theme or Premium Theme), Custom Plugin Development. Hands on Experience on 3rd Party Php Extension like Chilkat, nSoftware.

Recent Posts

  • Step-by-Step: Diagnosing indexing lock conflicts and high CPU during bulk stock updates on DigitalOcean Servers
  • How to Debug and Fix memory leaks and socket exhaustion in daemon processes in Modern C++ Applications
  • Infrastructure as Code: Provisioning Secure PHP Clusters on DigitalOcean Using Terraform
  • Fixing Slow Largest Contentful Paint (LCP) caused by unoptimized database queries in Legacy Laravel Codebases Without Breaking API Contracts
  • An Auditor’s Checklist for Securing Laravel Backends on Google Cloud

Copyright © 2026 · Vinay Vengala