Think in terms of how data flows through memory and execution: what is copied, what is referenced, and what changes after each operation.
Memory behavior is mostly reference counting plus cyclic garbage collection. Objects are reclaimed when unreachable.
- Track strong references that keep objects alive.
- Detect cycles for container-heavy designs.
- Distinguish shallow copy from deep copy.
- Use explicit cleanup for external resources.
In production systems, memory issues are often lifetime and ownership issues, not syntax issues. Ownership boundaries must be explicit.
- Define who owns long-lived objects.
- Minimize hidden global references and caches.
- Audit thread/process boundaries for copy/share semantics.
- Monitor memory with repeatable load scenarios.
- Why does deleting one variable name not always free object memory?
- What is the difference between reference counting cleanup and cyclic GC cleanup?
- How does
copy.copydiffer fromcopy.deepcopyfor nested data?
- What ownership mistakes usually cause memory growth in long-running apps?
- Why can global caches become hidden memory leaks?
- What memory model checks do you run before introducing concurrency?
Understand how this topic runs in actual program flow:
- Read statement
- Resolve type/object/reference
- Execute operation (assignment, mutation, call, return)
- Update memory state (stack/heap bindings)
- Re-check final output from updated state
When you see ANY question:
- Primitive? → value
- Object? → reference
- Primitive → stack
- Object → heap (via reference)
- Primitive → copy value
- Object → copy reference
- Field change → mutation
new→ new object (reassignment)
- Always pass-by-value
- Object → reference copied