Memory management is one of the most critical aspects of any programming language. In PHP, a language designed to handle dynamic and complex web applications, memory is allocated and freed automatically. This automatic process is powered by Garbage Collection (GC).
Garbage Collection (GC) is the process by which PHP identifies and frees up memory occupied by variables, objects, or arrays that are no longer in use.
PHP automatically manages memory through reference counting and cyclic garbage collection. This ensures that scripts do not consume more memory than necessary, avoiding memory leaks and performance degradation.
Reference Counting
At its core, PHP uses reference counting to track how many variables reference a particular piece of memory (zval container).
- Example:
$a = "Hello"; // Reference counter = 1 $b = $a; // Reference counter = 2 unset($a); // Reference counter = 1 unset($b); // Reference counter = 0 => Memory freed
This mechanism works well in most cases, but it fails with circular references.
The Problem of Circular References
A circular reference occurs when two or more objects reference each other, preventing their reference counters from ever reaching zero.
- Example:
class Node { public $child; } $a = new Node(); $b = new Node(); $a->child = $b; $b->child = $a; // Both $a and $b reference each other => reference count never reaches 0
In such cases, PHP's reference counting alone cannot clean up the memory. This leads to memory leaks.
To solve this, PHP introduced Cyclic Garbage Collection starting with PHP 5.3.
Cyclic Garbage Collection
The cyclic garbage collector (GC) is responsible for detecting and cleaning up circular references.
- How It Works:
Garbage Collection Process
The process can be broken into three phases:
Controlling Garbage Collection
PHP provides several functions to control the GC:
- Enable/Disable GC
gc_enable(); // Enable GC gc_disable(); // Disable GC
- Check GC Status
if (gc_enabled()) { echo "Garbage Collection is enabled"; }
- Trigger GC Manually
gc_collect_cycles(); // Force collection of all existing garbage cycles
This is useful in long-running scripts (e.g., daemons, CLI tools, or large imports).
Configuration Directives for Garbage Collection
In php.ini, several directives influence memory management:
- Example:
zend.enable_gc = 1 gc_probability = 1 gc_divisor = 1000
This means that on average, 1 in 1000 allocations will trigger GC.
Performance Considerations
While GC prevents memory leaks, it comes with overhead.
- Best Practices:
Garbage Collection and PHP Versions
Garbage Collection in Real-World Applications
- Example: Long-running Worker
while (true) { $data = getDataFromQueue(); process($data); unset($data); gc_collect_cycles(); // prevent leaks in loops }
- Example: Object Graphs
When dealing with ORM frameworks (e.g., Doctrine, Eloquent), objects often reference each other. Without GC, large applications would leak memory quickly.
Monitoring Garbage Collection
You can monitor GC stats using:
gc_collect_cycles(); print_r(gc_status());
- Sample output:
Array ( [runs] => 3 [collected] => 25 [roots] => 0 )
Source: Orkhan Alishov's notes