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

Memory Management — Stack vs Heap

Compiler PHP 5.0+ Intermediate
debt(d7/e5/b7/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints list specialist tools — blackfire, php-meminfo, datadog — but these require deliberate instrumentation and profiling setup. Memory issues typically surface as 'memory_limit hit in production' (per code_pattern), meaning the problem is often silent until it manifests under real load. Not caught by compiler or default linters, and requires specialist tooling or production monitoring to detect, placing it between d5 and d9; d7 because production exposure is the primary discovery path even when tools exist.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix mentions several remediation steps: monitoring memory_get_peak_usage(), switching to generators for large datasets, adding unset() calls, and potentially upgrading PHP version. Common mistakes involve circular references, large array accumulation in loops, and long-running script patterns. These fixes are not a single-line swap — refactoring a loop to use generators or auditing long-running scripts for unset() calls touches multiple locations and requires rethinking data-flow patterns, but stops short of full architectural rework.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). The term applies_to web, cli, and queue-worker contexts — the full breadth of PHP usage. Long-running scripts (queue workers, CLI commands) are shaped by this constraint: every large dataset operation, every object accumulation pattern, and every loop must be considered through the lens of memory impact. The misconception that 'PHP's GC handles everything' means teams often build with no memory discipline, and correcting that shapes how generators, unset(), and reference patterns are used across the codebase.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception is explicitly stated: 'PHP developers don't need to understand memory management — PHP's GC handles allocation.' This is a credible but wrong belief that contradicts how PHP's reference-counting GC actually behaves with circular references. A competent developer from a managed-memory language (Java, Python, C#) would reasonably assume the GC handles cycles transparently, but PHP's refcount mechanism requires explicit intervention (unset(), gc_collect_cycles()) for cyclic structures. The trap is particularly dangerous in long-running processes where the 'obvious' GC-trusting approach silently accumulates leaks.

About DEBT scoring →

Also Known As

stack memory heap memory garbage collection ZendMM

TL;DR

The stack holds function call frames with fixed-size local variables — fast, automatic, limited. The heap holds dynamically allocated objects — flexible, managed by GC, slower.

Explanation

Stack memory: allocated at function call, freed at return. Stores: local variables, function parameters, return addresses. Fixed size (typically 8MB on Linux). Extremely fast — just a pointer increment. Stack overflow: too many nested calls exhaust the stack. Heap memory: allocated with new/malloc, freed by garbage collection or explicit free. Stores: objects, arrays, large data structures. PHP uses a reference-counting GC with cycle collector. ZendMM (Zend Memory Manager) manages PHP's heap. PHP does not expose stack vs heap to the developer — all variables are reference-counted heap values by default.

Common Misconception

PHP developers don't need to understand memory management — PHP's GC handles allocation, but developers cause memory issues through circular references, large object accumulation, and not using generators for large datasets.

Why It Matters

PHP processes that accumulate objects in long-running scripts (queue workers, CLI commands) can exhaust memory — understanding reference counting explains why circular references cause leaks and why generators save memory.

Common Mistakes

  • Circular references without unset() — PHP's refcount GC handles most cycles but cyclic destruction order can cause leaks.
  • Appending to a huge array in a loop instead of using generators.
  • Not calling unset() on large variables in long-running scripts.
  • Using PHP's GC with long-lived objects — gc_collect_cycles() can be called manually for cycle collection.

Code Examples

✗ Vulnerable
// Memory leak via circular reference:
class Node {
    public ?Node $parent = null;
    public array $children = [];
}
$parent = new Node();
$child  = new Node();
$parent->children[] = $child;
$child->parent      = $parent; // Circular: parent→child→parent
unset($parent, $child); // Refcount never reaches 0 — leak!
// PHP cycle GC eventually collects these, but slowly
✓ Fixed
// Break circular references explicitly:
unset($child->parent); // Break cycle before unset
unset($parent, $child); // Now refcount reaches 0 immediately

// Or use WeakReference for back-references:
class Node {
    public ?\WeakReference $parent = null; // Does not increment refcount
}
$child->parent = \WeakReference::create($parent);
// When $parent is unset, WeakReference returns null — no cycle

Added 16 Mar 2026
Edited 22 Mar 2026
Views 93
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 2 pings W 3 pings T 6 pings F 1 ping S 6 pings S 3 pings M 2 pings T 0 pings W 0 pings T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 2 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 22 Amazonbot 18 Perplexity 10 Google 7 Ahrefs 5 SEMrush 5 Unknown AI 4 PetalBot 2 ChatGPT 1 Majestic 1 Claude 1 Meta AI 1
crawler 74 crawler_json 2 pre-tracking 1
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Monitor memory_get_peak_usage() in production; use generators for large datasets; unset large variables when done; use PHP 7+ which halved memory usage vs PHP 5
📦 Applies To
PHP 5.0+ web cli queue-worker
🔗 Prerequisites
🔍 Detection Hints
memory_limit hit in production; loading entire CSV database result into array; 100k+ objects in memory simultaneously
Auto-detectable: ✓ Yes blackfire php-meminfo datadog
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Medium Context: File
CWE-401 CWE-400


✓ schema.org compliant