• 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 » Step-by-Step: Diagnosing PHP-FPM memory consumption per child process on Linode Servers

Step-by-Step: Diagnosing PHP-FPM memory consumption per child process on Linode Servers

Understanding PHP-FPM Memory Limits

PHP-FPM (FastCGI Process Manager) is a popular alternative PHP FastCGI implementation with some additional features useful for sites of any size, especially busy ones. A common challenge on production servers, particularly those hosted on Linode where resource management is critical, is understanding and controlling the memory consumption of PHP-FPM worker processes. Uncontrolled memory usage can lead to OOM (Out Of Memory) killer interventions, application slowdowns, and server instability. This guide provides a step-by-step approach to diagnosing and pinpointing memory usage per PHP-FPM child process.

Initial Assessment: System-Wide Memory Usage

Before diving into PHP-FPM specifics, it’s crucial to get a baseline of overall system memory. This helps determine if PHP-FPM is indeed the primary culprit or if other services are contributing significantly.

Using `htop` for Real-time Monitoring

htop is an interactive process viewer for Linux. It provides a real-time, sortable, and filterable view of running processes. Install it if you don’t have it:

  • sudo apt update && sudo apt install htop -y (Debian/Ubuntu)
  • sudo yum update && sudo yum install htop -y (CentOS/RHEL)

Once installed, run htop. Pay attention to the memory bar at the top and sort processes by memory usage (press ‘M’). Look for processes named php-fpm or similar. Note the RES (Resident Memory Size) column for these processes.

System Memory Commands

Several command-line tools offer snapshots of memory usage:

  • free -h: Displays total, used, free, shared, buffer/cache, and available memory in a human-readable format.
  • vmstat 1: Reports virtual memory statistics every second. Look at the si (swap in) and so (swap out) columns, which indicate memory pressure.
  • ps aux --sort=-%mem | head -n 10: Lists all running processes, sorted by memory usage in descending order, showing the top 10.

If the total system memory is consistently high, and php-fpm processes are among the top consumers, proceed to the next steps.

Identifying PHP-FPM Configuration Parameters

PHP-FPM’s memory behavior is heavily influenced by its configuration. The primary configuration file is typically located at /etc/php/[version]/fpm/php-fpm.conf or /etc/php-fpm.conf, with pool-specific configurations often found in /etc/php/[version]/fpm/pool.d/www.conf (or a custom pool name).

Key Configuration Directives

The most relevant directives for managing child process memory are:

  • pm.max_children: The maximum number of child processes that will be spawned.
  • pm.start_servers: The number of child processes to start when PHP-FPM starts.
  • pm.min_spare_servers: The minimum number of idle spare servers.
  • pm.max_spare_servers: The maximum number of idle spare servers.
  • pm.process_idle_timeout: The number of seconds after which an idle process will be killed.
  • pm.max_requests: The maximum number of requests each child process will execute before respawning. This is crucial for preventing memory leaks from accumulating over time.

The pm (Process Manager) setting can be static, dynamic, or ondemand. dynamic is the most common and allows PHP-FPM to scale the number of workers based on load, within the defined spare server limits.

Measuring Memory Usage Per Process

To accurately diagnose memory issues, we need to measure the memory consumed by individual PHP-FPM worker processes. This can be done using system tools and by instrumenting PHP code.

Using `ps` with Specific Fields

The ps command can be used to extract specific memory-related information for PHP-FPM processes. We’ll filter for processes owned by the user that PHP-FPM runs as (often www-data or nginx) and then display their Resident Set Size (RSS) and Virtual Memory Size (VMS).

First, identify the user PHP-FPM runs as. Check your php-fpm.conf or www.conf for the user and group directives. Let’s assume it’s www-data.

Run the following command to see the memory usage of all php-fpm processes:

  • ps -ylC php-fpm --sort:rss | awk '{ sum += $8 } END { print "Total memory usage: " sum / 1024 " MB" }'
  • ps aux | grep 'php-fpm: pool' | grep -v grep

The second command is more illustrative. It shows the User, PID, %CPU, %MEM, VSZ (Virtual Memory Size), RSS (Resident Set Size), TTY, STAT, START, TIME, and COMMAND for each PHP-FPM worker. The RSS column is the most relevant for actual physical memory consumption.

Scripting Memory Checks

For more automated monitoring, you can create a simple shell script. This script will periodically check the average and maximum RSS of PHP-FPM processes.

Create a file named check_php_fpm_memory.sh:

#!/bin/bash

# User PHP-FPM runs as (e.g., www-data, nginx)
PHP_FPM_USER="www-data"

# Get PIDs of php-fpm worker processes
PIDS=$(pgrep -f "php-fpm: pool" | xargs)

if [ -z "$PIDS" ]; then
    echo "No PHP-FPM worker processes found."
    exit 1
fi

TOTAL_RSS=0
MAX_RSS=0
NUM_PROCESSES=0

for PID in $PIDS; do
    # Get RSS for the current PID
    # Using /proc/[pid]/statm for more granular memory info
    # The second field in statm is resident set size (pages)
    RSS_PAGES=$(awk '{print $2}' /proc/$PID/statm 2>/dev/null)
    if [ -n "$RSS_PAGES" ]; then
        # Convert pages to KB (assuming 4KB page size)
        RSS_KB=$((RSS_PAGES * 4))
        TOTAL_RSS=$((TOTAL_RSS + RSS_KB))
        if [ "$RSS_KB" -gt "$MAX_RSS" ]; then
            MAX_RSS=$RSS_KB
        fi
        NUM_PROCESSES=$((NUM_PROCESSES + 1))
    fi
done

if [ "$NUM_PROCESSES" -gt 0 ]; then
    AVG_RSS_KB=$((TOTAL_RSS / NUM_PROCESSES))
    AVG_RSS_MB=$(awk "BEGIN {printf \"%.2f\", $AVG_RSS_KB / 1024}")
    MAX_RSS_MB=$(awk "BEGIN {printf \"%.2f\", $MAX_RSS / 1024}")
    TOTAL_RSS_MB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_RSS / 1024 / 1024}")

    echo "PHP-FPM Memory Report:"
    echo "----------------------"
    echo "Number of processes: $NUM_PROCESSES"
    echo "Average RSS per process: $AVG_RSS_MB MB"
    echo "Maximum RSS per process: $MAX_RSS_MB MB"
    echo "Total RSS for all processes: $TOTAL_RSS_MB MB"
else
    echo "Could not retrieve memory information for PHP-FPM processes."
fi

Make the script executable:

chmod +x check_php_fpm_memory.sh

Run it to get an immediate report:

./check_php_fpm_memory.sh

You can schedule this script using cron to log memory usage over time and identify trends or spikes.

Debugging Memory Leaks within PHP Applications

If individual PHP-FPM processes are consuming excessive memory and this memory usage grows over time (even with pm.max_requests set), it strongly suggests a memory leak within your PHP application code or a third-party library. PHP itself has garbage collection, but it’s not perfect, and certain patterns can lead to leaks.

Using Xdebug for Memory Profiling

Xdebug is an invaluable tool for debugging PHP, including memory profiling. You can configure Xdebug to generate a call graph that includes memory usage information.

Ensure Xdebug is installed and configured in your php.ini. Key settings for memory profiling:

[xdebug]
xdebug.mode = profile,develop
xdebug.output_dir = /tmp/xdebug_profiling
xdebug.profiler_enable_trigger = 1
xdebug.profiler_trigger_value = "XDEBUG_PROFILE"
xdebug.profiler_output_name = "cachegrind.out.%s"
xdebug.max_nesting_level = 1000

With these settings, when a request contains the GET/POST parameter or cookie XDEBUG_PROFILE, Xdebug will generate a cachegrind file in the specified output directory. You can then analyze this file using tools like KCacheGrind (Linux), QCacheGrind (Windows), or Webgrind (web-based).

To trigger profiling for a specific request, append ?XDEBUG_PROFILE=1 to the URL. For POST requests or AJAX calls, you might need to set a cookie or use a tool like Postman to include the trigger.

Manual Memory Tracking in PHP

For targeted debugging, you can manually track memory usage within your PHP scripts. The memory_get_usage() and memory_get_peak_usage() functions are essential.

<?php
// Start of script or a specific function/block
$memory_start = memory_get_usage();
$peak_memory_start = memory_get_peak_usage();

// ... your code here ...

// After a significant operation or at the end of a request
$memory_end = memory_get_usage();
$peak_memory_end = memory_get_peak_usage();

echo "Memory usage at this point: " . ($memory_end - $memory_start) / 1024 . " KB\n";
echo "Peak memory usage since start: " . ($peak_memory_end - $peak_memory_start) / 1024 . " KB\n";
?>

By strategically placing these calls, you can isolate which parts of your code are responsible for significant memory allocations. If you see a continuous increase in memory usage across multiple requests within the same child process (before pm.max_requests is hit), you’ve likely found a leak.

Tuning PHP-FPM Configuration for Memory Control

Once you have a good understanding of your application’s memory footprint and the behavior of PHP-FPM processes, you can tune the configuration.

Setting Appropriate `pm.max_requests`

This is often the first line of defense against memory leaks. If your average PHP script uses 20MB of memory, and you have a leak that adds 1MB per request, setting pm.max_requests to 100 means a process will restart before it consumes an additional 100MB. A common starting point is 500 or 1000, but this should be adjusted based on your application’s memory profile.

; In your pool.d/www.conf
pm.max_requests = 500

Adjusting `pm.max_children`

This directive, along with pm.start_servers and pm.min/max_spare_servers, controls the total number of PHP-FPM processes. The total memory consumed by PHP-FPM will be roughly pm.max_children multiplied by the average memory usage per process. Ensure your server has enough RAM to accommodate this.

A common formula to estimate pm.max_children:

pm.max_children = (Total RAM - RAM used by OS & other services) / Average PHP-FPM process memory usage

For example, if your Linode instance has 4GB RAM (4096MB), and other services use ~1GB, leaving 3GB (3072MB) for PHP-FPM, and your average PHP-FPM process uses 50MB, you could set pm.max_children to approximately 3072MB / 50MB = 61.

; In your pool.d/www.conf
pm = dynamic
pm.max_children = 60
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500

Remember to restart PHP-FPM after making configuration changes:

sudo systemctl restart php[version]-fpm

Replace [version] with your PHP version (e.g., php8.1-fpm).

Conclusion

Diagnosing PHP-FPM memory consumption on Linode servers requires a systematic approach. Start with system-wide monitoring, then drill down into PHP-FPM’s configuration and individual process memory usage. Utilize tools like htop, ps, and custom scripts for measurement. For application-level issues, leverage Xdebug for profiling and manual memory tracking within PHP code. Finally, tune PHP-FPM’s process management directives, particularly pm.max_requests and pm.max_children, to maintain a stable and performant environment.

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 thread pools deadlock during concurrent ActiveRecord transaction processing on Linode Servers
  • Securing Your E-commerce APIs: Preventing SQL Injection (SQLi) in customized checkout queries in WooCommerce Implementations
  • Disaster Recovery 101: Architecting Auto-Failovers for MySQL and Ruby Deployments on Linode
  • High-Throughput Caching Strategies: Scaling MySQL for Perl Application APIs
  • Disaster Recovery 101: Architecting Auto-Failovers for DynamoDB and Laravel Deployments on DigitalOcean

Copyright © 2026 · Vinay Vengala