DEV Community

Cover image for The Secret Life of JavaScript: The Garbage Collector
Aaron Rose
Aaron Rose

Posted on

The Secret Life of JavaScript: The Garbage Collector

How memory leaks happen and how the Mark-and-Sweep algorithm works.


Timothy was staring at the dashboard he was building. It was getting slow. Sluggish.

"I don't understand," he said. "I am just creating objects. I'm not running heavy calculations. Why is the browser freezing?"

Margaret walked to the chalkboard and drew a large rectangle.

"Because you are running out of space, Timothy. This is the Heap."

The Heap (Memory is Finite)

"The Heap is where JavaScript stores objects, arrays, and functions," Margaret explained. "It is large, but it is not infinite. If you keep allocating memory without freeing it, you exhaust the available space. The browser freezes."

"But I don't free anything," Timothy said. "I just move to the next function."

"You don't have to free memory manually," Margaret corrected. "The Garbage Collector (GC) does it for you. But it follows very strict rules."

Reachability (Mark-and-Sweep)

Margaret drew a small circle at the top of the board and labeled it Root (Window).

"How does the GC know which objects to keep and which to destroy?" she asked.

"It checks if I'm using them?"

"No," Margaret said. "It checks if they are Reachable."

She drew arrows connecting the Root to various objects.

"This is the Mark-and-Sweep algorithm," she said.

  1. The Roots: The GC starts at the "Roots" (The Global window object and the current Call Stack).
  2. The References: It follows every reference (every variable, every property). If an object is connected to a Root, it is marked "Safe."
  3. The Sweep: Any object that cannot be reached from a Root is considered garbage. It is marked for deletion and removed during the next GC cycle.

The Disconnect

Margaret erased a line on the board.

let user = { name: "Timothy" }; 
// 1. The 'user' variable is a Reference from the Root to the object.

user = null; 
// 2. The Reference is broken.

Enter fullscreen mode Exit fullscreen mode

"When you set user = null," Margaret explained, "you didn't delete the object. You just broke the Reference."

"So the object is stranded?" Timothy asked.

"Exactly. The next time the GC runs, it will start at the Root, try to find that object, and fail. Since it is unreachable, the space is reclaimed."

The Memory Leak

Timothy looked at his slow code. "So if my app is slow, it means I am holding onto objects I don't need?"

"Yes," Margaret said. "You have a Memory Leak. You are accidentally keeping a Reference alive."

She wrote a common trap on the board:

function startDashboard() {
    const hugeData = new Array(100000).fill("Data");

    // The Trap:
    window.addEventListener('resize', () => {
        console.log(hugeData.length);
    });
}

Enter fullscreen mode Exit fullscreen mode

"Trace the References," Margaret commanded.

Timothy looked at the diagram.

  1. The Root (Window) has an Event Listener attached to it (resize).
  2. The Listener is a function that uses hugeData.
  3. Because of Closure, the Listener must hold a reference to hugeData.

"I see it," Timothy realized. "The Window holds the Listener. The Listener holds the Data."

"Correct," Margaret said. "Even if startDashboard finishes running, that connection remains. The GC sees a clear path from the Root to your massive array. It cannot delete it."

The Solution

"How do I fix it?" Timothy asked.

"You must break the reference," Margaret said.

She added the cleanup code:

window.removeEventListener('resize', myListener);

Enter fullscreen mode Exit fullscreen mode

"Remove the listener," she said. "The connection breaks. The huge data becomes unreachable. The Garbage Collector sweeps it away, and your browser breathes again."

The Conclusion

"Memory management isn't about micromanaging every object," Margaret concluded, wiping the chalk dust from her hands. "It's about understanding the invisible connections that keep data alive. Break the connections you don't need, and let the garbage collector do its job."


Aaron Rose is a software engineer and technology writer at tech-reader.blog and the author of Think Like a Genius.

Top comments (2)

Collapse
 
alptekin profile image
alptekin I.

Hi, thanks for this post.
I really like your explaining interesting concepts in stories.

in a world where the RAMs are more abundant and cheaper, and since web devs work on laptops/servers not chips, a typical JS developer may easily be inclined to not-think about memory management -true, it is not as C++ development in the end- but i suppose it can affect web performance for certain cases.

I suppose event handlers are the easiest trap, as you defined. In react, as they are mostly defined in useEffects, it must be cared and removed during the unmounting of the component, which is something that can be forgotten in haste (speaking from experience)

Collapse
 
aaron_rose_0787cc8b4775a0 profile image
Aaron Rose

❤💯🙏