{
    "slug": "garbage_collection",
    "term": "Garbage Collection",
    "category": "compiler",
    "difficulty": "advanced",
    "short": "Automatic memory management that reclaims objects no longer reachable by the program — PHP uses reference counting with a cycle collector for circular references.",
    "long": "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.",
    "aliases": [
        "reference counting",
        "cycle collector",
        "GC",
        "memory management"
    ],
    "tags": [
        "compiler",
        "memory",
        "php",
        "performance"
    ],
    "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."
    ],
    "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."
    ],
    "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."
    ],
    "related": [
        "memory_leak",
        "weak_references",
        "php_fpm",
        "processes_vs_threads"
    ],
    "prerequisites": [
        "memory_management",
        "php_weak_map",
        "php_fpm"
    ],
    "refs": [
        "https://www.php.net/manual/en/features.gc.php",
        "https://www.php.net/manual/en/class.weakreference.php",
        "https://www.php.net/manual/en/function.gc-collect-cycles.php"
    ],
    "bad_code": "// Circular reference — not immediately freed:\nclass Node {\n    public ?Node $parent = null;\n    public array $children = [];\n}\n$root = new Node();\n$child = new Node();\n$root->children[] = $child;\n$child->parent = $root; // Circular: root → child → root\nunset($root, $child); // Reference count > 0 — not freed immediately\n// Freed later by cycle collector — or manually: gc_collect_cycles()",
    "good_code": "// Break circular references explicitly:\nfunction processTree(Node $root): void {\n    foreach ($root->children as $child) processTree($child);\n    // Break circular refs before returning:\n    foreach ($root->children as $child) $child->parent = null;\n    $root->children = [];\n}\n// Or use WeakReference for parent pointers — does not prevent GC\nclass Node {\n    public ?WeakReference $parent = null; // Weak — GC can collect parent\n}",
    "example_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.",
    "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",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-04-28",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/garbage_collection",
        "html_url": "https://codeclaritylab.com/glossary/garbage_collection",
        "json_url": "https://codeclaritylab.com/glossary/garbage_collection.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[Garbage Collection](https://codeclaritylab.com/glossary/garbage_collection) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/garbage_collection"
            }
        }
    }
}