January 3 2025
Memory Without Mystery
How to understand references, lifecycle, mutation, and leaks without turning the topic into a compiler lecture.
Andrews Ribeiro
Founder & Engineer
4 min Intermediate Frontend
The problem
Memory in JavaScript is often taught as a bag of disconnected words:
- stack
- heap
- garbage collector
- reference
People walk away knowing the vocabulary but still not being able to answer the questions that matter:
- Why is this object still alive?
- Why did changing it here affect some other part of the app?
- Why does this process keep growing in RAM?
Without a simple model, everything starts to feel like “JavaScript being weird.”
Mental model
You do not need to turn this into a compiler class.
Keep these three ideas:
- simple values are usually cheap to copy
- objects, arrays, and functions usually move around by reference
- memory can only be freed when nothing in the program can still reach that value
Short version:
Memory gets easier when you think in terms of references, reachability, and lifecycle.
Breaking it down
Was it copied or shared?
This is the first filter.
If you do this:
const a = { name: 'Ana' }
const b = a
you did not create two objects.
You created two variables pointing to the same object.
If you forget that, a large part of mutation bugs starts right there.
Who can still reach this value?
A value does not disappear just because you stopped looking at it.
It disappears when the whole program stops being able to reach it.
That is why objects stay alive when they are still held by:
- a cache
- a global array
- a
Map - a closure
- an event listener
Should this value still exist right now?
This question is more useful than talking about the garbage collector like it is some mystical cleanup robot.
The real issue is not “did the GC run.”
The real issue is:
- should this data still be here?
- does this cache have an eviction rule?
- did we remove this listener?
A leak is usually accumulation, not black magic
People often imagine a memory leak as some hidden hole inside the runtime.
In practice, the common cases are less dramatic:
- a list that only grows
- a cache without expiration
- a big object trapped in a closure
- a session map that never removes old entries
So the problem is usually more about lifecycle design than about the engine losing control.
When you investigate a memory or mutation issue, ask:
- Was this value copied, or are two variables sharing the same reference?
- Who can still access this object?
- Should this value still exist right now?
- Is some array, cache, closure, or
Mapgrowing without cleanup?
Simple example
Look at this common trap:
const user = { name: 'Ana' }
const sameUser = user
sameUser.name = 'Bia'
console.log(user.name)
The output is:
Bia
That did not happen because JavaScript copied the object badly.
user and sameUser point to the same object in memory. When you change sameUser.name, you are also changing user.name.
That detail explains a lot of “mysterious” mutations in:
- shared state
- React apps
- Node services
- legacy code with too many side effects
Common mistakes
- assuming that assigning an object to another variable creates a fresh copy
- forgetting that shared references spread side effects across the app
- accumulating data in caches, stores, arrays, or
Maps without cleanup rules - talking about the garbage collector as if it can repair weak architecture on its own
How a senior thinks
More experienced engineers look at memory in terms of ownership and reachability.
The reasoning usually sounds like this:
The problem is not only where this data was created. The problem is who can still reach it and how long we are letting it stay alive.
That change in framing improves debugging fast:
- leaks stop feeling abstract
- mutation stops feeling random
- lifecycle becomes visible
What the interviewer wants to see
In interviews, what usually matters is whether you can connect the theory to a real bug.
- you understand the difference between a real copy and a shared reference
- you can explain why a “deleted” value still exists in memory
- you can tie the concept to a real issue like silent mutation or rising RAM usage
A strong answer often sounds like this:
I think about memory as lifecycle. If some cache, listener, or closure can still reach the value, it is still alive, even if I no longer want it there.
Garbage collection helps clean up what became unreachable. It does not fix an architecture that keeps holding the reference.
Quick summary
What to keep in your head
- A lot of memory problems start with shared references and weak lifecycle design, not with the garbage collector somehow failing.
- An object can stay alive even after you stopped caring about it, as long as some part of the app can still reach it.
- A mysterious mutation is often just two variables pointing at the same object.
- In interviews, strong answers connect memory to real bugs instead of giving an abstract heap lecture.
Practice checklist
Use this when you answer
- Can I explain the difference between copying a value and sharing a reference?
- Can I investigate who can still reach an object that should be gone?
- Can I spot caches, arrays, listeners, and closures that keep accumulating data?
- Can I explain why garbage collection does not fix bad ownership or bad lifecycle design by itself?
You finished this article
Share this page
Copy the link manually from the field below.