第25天:记忆
#javascript #100daysofcode #day25

内存ð§管理是任何编程语言的关键方面,JavaScript也不例外。了解JavaScript如何处理内存对于构建高效和性能应用程序至关重要。

ð记忆分配

在JavaScript中,根据需要为变量和对象分配内存。内存分配中的关键概念之一是堆栈和堆之间的区别。

ð¥堆栈

堆栈是存储区域,用于存储原始数据类型和功能调用信息。具有已知固定尺寸的变量,例如数字和布尔值,存储在堆栈上。此内存有效地管理,因为它遵循了最后的首次出局(LIFO)方法。

function calculateSum(a, b) {
  // `a` and `b` are stored on the stack
  return a + b;
}

ð堆

堆是用于存储具有动态大小的对象和变量的内存区域。使用new关键字创建的数组和对象之类的对象存储在堆上。此内存需要更复杂的管理,因为它涉及跟踪参考并确保正确清理。

const largeArray = [1, 2, 3, 4, 5];
// `largeArray` is stored on the heap

ð记忆生命周期

Image description

  • 分配:内存分配是指保留计算机内存的一部分以存储数据。在JavaScript中,通常是在创建变量,对象或数组时完成的。
   let num = 42; // Allocating memory for a number
   let arr = [1, 2, 3]; // Allocating memory for an array
  • 用法:一旦分配了内存,就可以将其用于存储数据并执行操作。正确的内存使用可确保最佳性能。
   let bigArray = new Array(1000000); // Using memory to store a large array
   for (let i = 0; i < bigArray.length; i++) {
     bigArray[i] = i * 2; // Utilizing memory for data storage
   }
  • 版本:不再需要释放不再需要的内存以防止记忆泄漏。在JavaScript中,当变量脱离范围时,内存将自动释放。
   function example() {
     let localVar = 'I will be released'; // Memory for localVar is released after the function call
     // Code utilizing localVar
   }

ð垃圾收集

JavaScript使用自动垃圾收集来收回由不再可用或需要的对象所占据的内存。最常见的垃圾收集算法是 Mark-and-sweep 算法:

  1. 标记:垃圾收集器标记所有可从根(全局对象,局部变量等)到达的对象。

  2. 扫扫:然后它扫过内存,处理的记忆被未标记为可触及的对象所占据的内存。

let obj1 = { ref: null };
let obj2 = { ref: null };
obj1.ref = obj2;
obj2.ref = obj1;
// Even though obj1 and obj2 reference each other, they will be marked for garbage collection if not reachable from the root.

ð¥内存泄漏

内存泄漏发生时,当不再需要的内存不再发布时,导致应用程序的内存使用量会随着时间的推移而增长。

  1. 意外的全局变量:应该具有本地范围的变量成为全局,阻止它们被收集到垃圾。

  2. 关闭:即使不再需要在外部变量之后,保留对外部变量的关闭。

  3. 未使用的事件听众:忘记删除事件听众可以将对象保存在内存中。

// Example of a memory leak due to a closure
function setupCounter() {
  let count = 0;
  setInterval(() => {
    console.log(count++);
  }, 1000);
}
// The closure in setInterval retains a reference to the 'count' variable, preventing it from being garbage collected.

例子

考虑一个场景,其中Web应用程序动态添加和删除DOM中的元素而无需正确清理

const container = document.getElementById('container');

function addElement() {
  const element = document.createElement('div');
  container.appendChild(element);
}

function removeElements() {
  container.innerHTML = ''; // Elements are removed from the DOM, but references may still exist
}

// Calling addElement multiple times
addElement();
addElement();

removeElements(); // Elements are removed from the DOM, but references remain

预防:删除所有事件的听众,参考和清理,在动态添加的元素之前,然后将其从DOM中删除。