← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Garbage Collection

compiler PHP 5.3+ Advanced

Also Known As

reference counting cycle collector GC memory management

TL;DR

Automatic memory management that reclaims objects no longer reachable by the program — PHP uses reference counting with a cycle collector for circular references.

Explanation

PHP's primary GC is reference counting: each value tracks how many variables point to it; when the count reaches 0, the value is freed immediately. Problem: circular references (A → B → A) never reach 0. PHP's cycle collector (since 5.3) detects and frees circular reference groups. In PHP 8, the GC is more efficient. Long-running processes (queue workers, PHP-FPM long-lived workers) accumulate memory through leaks or slow GC; calling gc_collect_cycles() manually in batch jobs can reduce memory usage.

Diagram

flowchart TD
    subgraph Reference Counting
        OBJ[Object<br/>refcount=1] -->|assign to 2nd var| RC2[refcount=2]
        RC2 -->|unset 1st var| RC1[refcount=1]
        RC1 -->|unset all| RC0[refcount=0<br/>free immediately]
    end
    subgraph Cycle Collector
        A[Object A<br/>points to B] -->|circular ref| B[Object B<br/>points to A]
        B --> A
        RC0B[Neither reaches 0<br/>both stranded]
        CYCLE[Cycle Collector<br/>runs periodically] -->|detects cycle| FREE[Frees both]
    end
    style RC0 fill:#238636,color:#fff
    style FREE fill:#238636,color:#fff

Watch Out

PHP's reference counter frees most objects immediately on unset, but circular references (parent→child→parent) are only reclaimed by the cycle collector — which runs periodically, not instantly. A long-running worker that builds trees without breaking cycles will leak memory steadily.

Common Misconception

PHP's garbage collector handles all memory automatically — circular references are only freed by the cycle collector, which runs periodically; large circular reference structures can accumulate in long-running scripts.

Why It Matters

PHP queue workers and long-running scripts that create circular references or large object graphs can slowly exhaust memory — understanding GC enables writing memory-efficient persistent PHP processes.

Common Mistakes

  • Not unsetting large arrays and objects after use in loops — reference count stays > 0 until scope ends.
  • Circular references in event listeners — object A registers a listener on object B; both hold references to each other.
  • Not calling gc_collect_cycles() in very long batch jobs — cycle collector runs automatically but not immediately.
  • PHP generators as memory optimisation — they yield one item at a time, but the generator object itself stays in memory.

Avoid When

  • Do not disable gc_disable() in long-running workers without a manual gc_collect_cycles() strategy — circular references accumulate silently until OOM.
  • Avoid creating large object graphs with circular parent/child references when a simple array or flat structure would suffice.

When To Use

  • Call gc_collect_cycles() explicitly after processing large batches of objects in long-running scripts to reclaim memory from circular references immediately.
  • Use WeakReference for cache or observer registrations where the GC should be free to collect the target without the reference preventing it.

Code Examples

💡 Note
The bad example builds a parent/child tree with circular references that the reference counter cannot free — memory grows per iteration. The fix nulls the parent reference before unsetting, breaking the cycle so memory is reclaimed immediately.
✗ Vulnerable
// Circular reference — not immediately freed:
class Node {
    public ?Node $parent = null;
    public array $children = [];
}
$root = new Node();
$child = new Node();
$root->children[] = $child;
$child->parent = $root; // Circular: root → child → root
unset($root, $child); // Reference count > 0 — not freed immediately
// Freed later by cycle collector — or manually: gc_collect_cycles()
✓ Fixed
// Break circular references explicitly:
function processTree(Node $root): void {
    foreach ($root->children as $child) processTree($child);
    // Break circular refs before returning:
    foreach ($root->children as $child) $child->parent = null;
    $root->children = [];
}
// Or use WeakReference for parent pointers — does not prevent GC
class Node {
    public ?WeakReference $parent = null; // Weak — GC can collect parent
}

Added 15 Mar 2026
Edited 28 Apr 2026
Views 56
AI edit PF Media Bot Claude Opus 4.5 on refs · 25 Apr 2026
Edits history 1 edit
  1. refs PF Media Bot Claude Opus 4.5 · 25 Apr 2026
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W 0 pings T 2 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Amazonbot 12 Perplexity 7 Unknown AI 3 Ahrefs 2 Majestic 1 Google 1 SEMrush 1
crawler 26 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
PHP uses reference counting with a cycle collector — call gc_collect_cycles() manually in long-running CLI scripts processing many objects to reclaim circular reference memory
📦 Applies To
PHP 5.3+ cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
Memory growing in queue worker over time; circular object references not freed; gc_collect_cycles() never called in long CLI batch
Auto-detectable: ✓ Yes blackfire php-meminfo
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: Medium Context: File

✓ schema.org compliant