阿里云主机折上折
  • 微信号
Current Site:Index > The garbage collection mechanism

The garbage collection mechanism

Author:Chuan Chen 阅读数:1161人阅读 分类: JavaScript

Basic Concepts of Garbage Collection Mechanism

JavaScript's garbage collection mechanism is an automatic memory management approach designed to free up memory occupied by objects that are no longer in use. When variables, objects, or functions are no longer referenced, the garbage collector marks this memory as reclaimable and releases it at an appropriate time. This mechanism alleviates the burden of manual memory management for developers but also introduces some performance considerations.

function createObjects() {
  const obj1 = { name: 'Object 1' };
  const obj2 = { name: 'Object 2' };
  obj1.ref = obj2;
  obj2.ref = obj1;
  return 'Objects created';
}

createObjects();
// Two mutually referencing objects are created here; they won't be reclaimed even after the function finishes executing

Mark-and-Sweep Algorithm

This is the most commonly used garbage collection algorithm in JavaScript. It consists of two phases: first, it traverses all reachable objects and marks them, then it clears unmarked objects. Reachable objects are those that can be accessed directly or indirectly from global objects.

let globalVar = {
  prop1: {
    prop2: {}
  }
};

// All objects in this object tree are reachable
globalVar.prop1.prop2.newProp = {};

// Break the reference
globalVar.prop1.prop2 = null;
// Now {newProp: {}} becomes unreachable and will be reclaimed

Reference Counting Algorithm

This is an older garbage collection strategy that determines whether to reclaim an object by tracking the number of references to it. When the reference count drops to zero, the object is reclaimed. However, this algorithm cannot handle circular references.

function referenceCounting() {
  let a = {};
  let b = {};
  a.ref = b;  // b's reference count is 1
  b.ref = a;  // a's reference count is 1
  
  // Even after leaving the scope, a and b's reference counts remain 1, so they won't be reclaimed
}

Garbage Collection in the V8 Engine

Modern JavaScript engines like V8 employ more sophisticated strategies. They divide the heap memory into two regions—the young generation and the old generation—and use different reclamation strategies:

  • The young generation uses the Scavenge algorithm, which reclaims memory via copying.
  • The old generation uses a combination of mark-and-sweep and mark-compact algorithms.
// Demonstrating object promotion to the old generation
function createLargeObjects() {
  let objects = [];
  for (let i = 0; i < 100000; i++) {
    objects.push(new Array(100).fill(0));
  }
  return objects[0];
}

const survivor = createLargeObjects();
// Long-lived objects are promoted to the old generation

Common Scenarios for Memory Leaks

Even with garbage collection, improper code can still lead to memory leaks:

  1. Accidental global variables
  2. Forgotten timers or callbacks
  3. Unreleased DOM references
  4. Improper use of closures
// Accidental global variable
function leakMemory() {
  leakedVar = 'This will leak';  // No var/let/const, becomes a global variable
}

// Uncleared timer
let data = fetchData();
setInterval(() => {
  process(data);
}, 1000);
// Even if data is no longer needed, the timer maintains a reference to it

// Unreleased DOM references
const elements = {
  button: document.getElementById('myButton'),
  container: document.getElementById('container')
};

// Even after removing elements from the DOM, the elements object retains references
document.body.removeChild(document.getElementById('container'));

Weak References and WeakMap/WeakSet

ES6 introduced WeakMap and WeakSet, which hold weak references to objects and do not prevent garbage collection. When an object has no other references, it will be reclaimed even if it exists in a WeakMap/WeakSet.

let obj = { data: 'important' };
const weakMap = new WeakMap();
weakMap.set(obj, 'some metadata');

const map = new Map();
map.set(obj, 'regular reference');

obj = null;  // Remove the strong reference

// The entry in weakMap will be automatically removed
// The entry in map still exists, preventing the object from being reclaimed

Manually Triggering Garbage Collection

Although not recommended, there are cases where manual garbage collection may be necessary:

// Non-standard method, available only in certain environments
if (typeof global.gc === 'function') {
  global.gc();
}

// A more general approach is to force memory allocation to indirectly trigger GC
function triggerGC() {
  const arr = [];
  for (let i = 0; i < 1000000; i++) {
    arr.push(new Array(100));
  }
}

Performance Optimization Tips

  1. Avoid creating unnecessary objects
  2. Release unneeded references promptly
  3. For large datasets, consider using object pools
  4. Use closures cautiously
  5. Process large arrays and objects in chunks
// Object pool example
class ObjectPool {
  constructor(createFn) {
    this.createFn = createFn;
    this.pool = [];
  }
  
  get() {
    return this.pool.length ? this.pool.pop() : this.createFn();
  }
  
  release(obj) {
    this.pool.push(obj);
  }
}

// Using an object pool
const pool = new ObjectPool(() => ({ x: 0, y: 0, data: null }));
const obj1 = pool.get();
// Use obj1...
pool.release(obj1);

Memory Analysis Tools

Modern browsers provide powerful memory analysis tools:

  1. Chrome DevTools' Memory panel
  2. Heap Snapshot functionality
  3. Allocation Timeline recording
  4. Performance Monitor
// Insert markers in code for easier analysis
console.profile('Memory analysis');
// Perform operations that may leak memory
console.profileEnd('Memory analysis');

Memory Management in Node.js

Node.js is based on the V8 engine but has some special considerations:

  1. Buffer objects are allocated in off-heap memory
  2. Need to pay attention to cleanup of event listeners
  3. Can adjust memory limits using --max-old-space-size
const { performance, PerformanceObserver } = require('perf_hooks');

// Monitor memory usage
const obs = new PerformanceObserver((items) => {
  const entry = items.getEntries()[0];
  console.log(`Heap used: ${entry.details.heapUsed / 1024 / 1024} MB`);
});
obs.observe({ entryTypes: ['gc'] });

// Simulate memory growth
let data = [];
setInterval(() => {
  data.push(new Array(10000).fill(0));
}, 100);

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.