# 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
// 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
// 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)
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)
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
// 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);
}
};