# Memory Management Optimization

> Debug memory leaks, profile memory usage, optimize allocations. Use when heap grows unexpectedly, OOM errors occur, or profiling shows memory bottleneck. Covers C++ (Valgrind, ASAN, RAII), Python (tracemalloc, objgraph), and general patterns.

- Skill: `majiayu000/memory-management-optimization` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds add majiayu000/memory-management-optimization`
- Raw SKILL.md: https://api.skillmd.com/api/skills/majiayu000/memory-management-optimization/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: majiayu000 (https://skillmd.com/u/majiayu000)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/majiayu000/memory-management-optimization

---


# Memory Management Optimization

**Persona:** Systems programmer who treats memory as a finite resource - every allocation has a cost, every leak is unacceptable.

## Process

1. **Baseline** - Measure current memory usage and allocation patterns
2. **Identify** - Find leaks, excessive allocations, or fragmentation
3. **Analyze** - Understand ownership, lifetimes, and allocation sites
4. **Fix** - Apply appropriate solution for the issue type
5. **Verify** - Confirm fix and ensure no regressions

## C++ Memory Debugging

### Valgrind (Linux)
```bash
# Leak detection
valgrind --leak-check=full --show-leak-kinds=all ./program

# Memory errors
valgrind --track-origins=yes ./program

# Massif for heap profiling
valgrind --tool=massif ./program
ms_print massif.out.*
```

| Valgrind Message | Meaning |
|------------------|---------|
| definitely lost | Leaked, no pointer exists |
| indirectly lost | Leaked via lost pointer |
| possibly lost | Pointer to middle of block |
| still reachable | Not freed at exit (often OK) |

### AddressSanitizer (All platforms)
```bash
# Compile with ASAN
clang++ -fsanitize=address -g program.cpp

# Also useful:
-fsanitize=leak          # Leak detection only
-fsanitize=memory        # Uninitialized reads (Clang)
-fsanitize=undefined     # UB detection
```

### RAII Patterns
```cpp
// BAD: Manual memory management
void bad() {
    int* p = new int[100];
    if (error) return;  // LEAK
    delete[] p;
}

// GOOD: RAII with smart pointers
void good() {
    auto p = std::make_unique<int[]>(100);
    if (error) return;  // Automatic cleanup
}
```

| Ownership | Use |
|-----------|-----|
| `unique_ptr` | Single owner, no sharing |
| `shared_ptr` | Multiple owners |
| `weak_ptr` | Observer, breaks cycles |
| Raw pointer | Non-owning reference only |

### Qt-Specific
```cpp
// Parent-child ownership
auto* child = new QWidget(parent);  // parent deletes child

// deleteLater for event loop safety
obj->deleteLater();

// Watch for:
// - Deleting QObject during signal handling
// - Objects without parents in long-lived containers
```

## Python Memory Debugging

### tracemalloc (Built-in)
```python
import tracemalloc

tracemalloc.start()

# ... code to profile ...

snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics('lineno')

for stat in top_stats[:10]:
    print(stat)
```

### objgraph (Reference cycles)
```python
import objgraph

# Find what's keeping objects alive
objgraph.show_backrefs(obj, max_depth=3)

# Find objects by type
objgraph.by_type('MyClass')

# Show growth between snapshots
objgraph.show_growth()
```

### Common Python Leaks
| Pattern | Fix |
|---------|-----|
| Circular references | `weakref`, break cycle |
| Global caches | Bounded cache, `@lru_cache(maxsize=N)` |
| Closures capturing | Copy values, use `weakref` |
| Event handlers | `disconnect()`, weak callbacks |
| Thread-local storage | Clean up on thread exit |

## General Optimization Patterns

### Object Pooling
```cpp
// Reuse objects instead of allocate/free
class ObjectPool {
    std::vector<Object*> available;
public:
    Object* acquire() {
        if (available.empty())
            return new Object();
        auto* obj = available.back();
        available.pop_back();
        return obj;
    }
    void release(Object* obj) {
        obj->reset();
        available.push_back(obj);
    }
};
```

### Arena Allocators
```cpp
// Bulk allocate, bulk free
class Arena {
    char* memory;
    size_t offset = 0;
public:
    void* alloc(size_t size) {
        void* ptr = memory + offset;
        offset += size;
        return ptr;
    }
    void reset() { offset = 0; }  // Free everything at once
};
```

### Avoiding Fragmentation
- Allocate similar-sized objects together
- Use fixed-size blocks where possible
- Consider memory-mapped files for large data
- Pre-allocate containers to final size

## Response Format

```markdown
## Memory Analysis

### Measurements
| Metric | Before | After |
|--------|--------|-------|
| Peak heap | 2.4 GB | 890 MB |
| Leak rate | 10 MB/hr | 0 |
| Allocs/sec | 50,000 | 8,000 |

### Issues Found
1. **Leak:** `src/cache.cpp:142` - HashMap entries never removed
2. **Fragmentation:** Small allocations in hot loop

### Fixes Applied
1. Added expiry to cache with LRU eviction
2. Replaced per-iteration allocs with object pool

### Verification
- Valgrind: 0 leaks
- 24hr soak test: stable at 450 MB
```

## Should NOT Attempt

- Premature optimization without profiling data
- Optimizing cold paths
- Changing allocation strategy without benchmarks
- Removing smart pointers for "performance"

## Escalation

- Concurrency in allocators → `systematic-debugging` skill (concurrency section)
- Architecture-level memory design → `backend-architect` agent
- Qt/C++ specific issues → `cpp-expert` agent
- Real-time allocation constraints → `cpp-expert` agent (handles embedded/real-time)

## When Blocked

If memory debugging stalls:
1. Ensure profiling tools are properly installed (Valgrind, ASAN, tracemalloc)
2. Verify debug symbols are present (build with -g)
3. Try alternative tool (ASAN if Valgrind too slow, tracemalloc for Python)
4. For stubborn leaks, add manual logging around suspected allocations
5. Report specific tool output and what's been tried

## Common Mistakes

| Mistake | Reality |
|---------|---------|
| "Smart pointers are slow" | Overhead is negligible, safety is worth it |
| "I'll add pooling everywhere" | Only pool when profiling shows benefit |
| "Valgrind is too slow" | Use ASAN for development, Valgrind for releases |
| "Python doesn't leak" | Reference cycles and caches leak constantly |

## Related Skills

- **systematic-debugging**: Debug memory issues methodically
- **cpp-expert**: C++ memory management, RAII, smart pointers
- **qt-qml-expert**: Qt object ownership, parent-child memory model

