How to Detect and Fix PHP Memory Leaks
Last updated: 5 November 2026. See the update log at the end. In a normal PHP-FPM request, a memory leak mostly does not exist: PHP frees everything when the request ends. The leaks people actually hit happen in processes that stay alive: queue workers, daemons, long import scripts, and application servers like Laravel Octane. The symptom is always the same. Memory climbs a little with every job…
Detecting and fixing PHP memory leaks can be a challenging task, but understanding the common causes and implementing the right strategies can help maintain optimal performance. PHP processes typically release memory when a request ends, but leaks can occur in long-running processes like queue workers, daemons, and application servers.
The main symptom is a gradual increase in memory usage until the system either runs out of memory or the process is terminated. This article outlines a step-by-step approach to confirm if a memory leak exists, identify the primary causes, and find solutions.
To test for memory leaks, create a function that prints memory usage at regular intervals during repeated work. If the memory usage plateaus, there is no leak. If it continues to rise steadily, a leak is likely present. The following PHP function demonstrates this approach:
```
function report(string $label): void {
printf('%s: %.1f MB (peak %.1f MB)\n',
$label,
memory_get_usage() / 1048576,
memory_get_peak_usage() / 1048576);
}
```
Next, run the same task multiple times and monitor memory usage. If it increases linearly, a leak is probable. PHP offers three useful functions for memory measurement:
1. memory_get_usage(): current allocation
2. memory_get_usage(true): system reservation
3. memory_get_peak_usage(): highest memory usage
With PHP 8.2, memory_reset_peak_usage() allows you to measure memory usage in smaller increments. In the provided example, a 50 MB string freed after a single request still left a peak value of 50.4 MB. After a reset, the peak usage dropped to 0.4 MB.
The first cause of memory leaks often stems from static arrays, singletons, or globals that accumulate data over time. By simulating 50,000 units of work and storing a 1 KB payload in a static cache, you can observe significant memory growth:
```
after 10000: 12.9 MB
after 50000: 62.5 MB
```
However, a bounded cache with a maximum size can prevent this issue. Alternatively, avoid caching when the data is inexpensive to reload. Another solution involves using WeakMap to tie cached data to the object it belongs to, allowing PHP to automatically remove weakly referenced entries:
```
$map = new WeakMap();
$user = new stdClass();
$map[$user] = [expensive_data];
echo count($map); // 1
unset($user);
echo count($map); // 0
```
In Laravel, avoid using singletons, static properties on services, or traits with static state, as these can lead to memory leaks when used in Octane or queue:work environments.
The second primary cause of memory leaks is circular references. PHP's garbage collector (GC) typically frees objects once they are no longer referenced, but cycles prevent this. To mitigate this, enable the GC and call gc_collect_cycles() periodically, especially when dealing with large object graphs or parsed documents. Breaking cycles by manually releasing references can also help:
```
class Report {
public $cb;
public $data;
public function __construct(bool $static) {
$this->data = str_repeat('x', 100000);
$this->cb = $static ? static fn() => 1 : fn() => $this->data;
}
}
```
In this case, circular references were freed after garbage collection, but disabling the collector made the issue worse.
By following these steps and implementing the suggested fixes, you can effectively detect and address PHP memory leaks, ensuring optimal performance in your applications.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.