Nodejs:怎样在 Node 和 Chrome 里产生一块 JS GC 无法回收的内存?

Nodejs:怎样在 Node 和 Chrome 里产生一块 JS GC 无法回收的内存?

貌似有 DOM 的时候要产生容易多了, 正在尝试手动创建看看 我现在了解到原因是 JS 在 DOM 节点上绑定事件加上闭包导致循环引用, 可我手动写一个测试, 跑起来很正常的, Chrome 里查看内存也没增多,


task = ->
  object =
    a: "name"
    b: ->
      c = object.name

  object.b()

call = (f, times) ->
  [1..times].forEach f

task_dom = ->
  object = document.createElement("div")
  object.onclick = ->
    
    a = object.innerHTML

start = ->
  call task, 100000
  call task_dom, 100000

看来理解有错… 有没有同学指点一下?


3 回复

在Node.js和Chrome浏览器中,生成一块JavaScript垃圾收集器(GC)无法回收的内存块通常涉及到循环引用或未正确处理的对象引用。在你的例子中,你提到DOM节点上的事件绑定和闭包可能导致了这个问题。以下是一些可能的原因以及如何通过示例代码来重现这一问题。

示例代码:生成无法回收的内存块

首先,让我们通过一个简单的Node.js示例来展示如何生成一块无法回收的内存。我们将使用global对象来创建一个全局变量,这样即使函数执行完毕,该变量仍然存在,从而阻止垃圾收集器回收它。

function createMemoryLeak() {
  const obj = {
    name: 'example',
    selfReference: null
  };

  // 创建一个循环引用
  obj.selfReference = obj;

  return obj;
}

function leakMemory(times) {
  for (let i = 0; i < times; i++) {
    createMemoryLeak();
  }
}

// 生成内存泄漏
leakMemory(100000);

在这个示例中,我们创建了一个对象obj,它包含一个指向自身的引用selfReference。这会导致内存泄漏,因为垃圾收集器无法释放这个对象,因为它总是有一个指向自身的引用。

使用DOM和事件处理程序

如果你在浏览器环境中工作,并且想要通过DOM元素和事件处理程序来创建内存泄漏,可以尝试以下代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Memory Leak Example</title>
</head>
<body>
  <script>
    function createDOMMemoryLeak() {
      const div = document.createElement('div');
      div.innerHTML = 'Click me';
      
      // 给元素添加点击事件
      div.addEventListener('click', function handleClick(event) {
        console.log('Clicked!');
        this.innerHTML = 'Clicked!';
      });
      
      // 将元素添加到DOM
      document.body.appendChild(div);
    }

    function leakDOMMemory(times) {
      for (let i = 0; i < times; i++) {
        createDOMMemoryLeak();
      }
    }

    // 生成内存泄漏
    leakDOMMemory(100000);
  </script>
</body>
</html>

在这个示例中,我们创建了大量的DOM元素,并为每个元素添加了一个事件监听器。由于这些事件监听器持有对元素的引用,而元素本身又可能持有其他引用,这可能会导致内存泄漏。

总结

通过以上示例,我们可以看到如何在Node.js和浏览器环境中创建内存泄漏。关键在于确保对象之间没有循环引用,并且在不再需要时正确地删除事件监听器和其他引用。希望这些示例能够帮助你更好地理解内存管理和垃圾收集机制。


JS引擎优化了

要生成一块 JavaScript 垃圾回收(GC)无法回收的内存,可以通过创建循环引用来实现。循环引用会导致垃圾回收器无法自动释放这些对象。下面是一个简单的 Node.js 示例,展示了如何通过创建循环引用来制造内存泄漏。

示例代码:

function createCircularReference() {
  let objA = {};
  let objB = {};

  // 创建循环引用
  objA.self = objA;
  objB.self = objB;

  // 将 objA 和 objB 保存在一个数组中
  let objects = [objA, objB];

  // 模拟长时间运行的任务
  setInterval(() => {
    objects.push({});
  }, 1000);
}

createCircularReference();

解释:

在这个例子中,我们创建了两个对象 objAobjB,并让它们互相引用。这会导致垃圾回收器无法自动释放这两个对象。此外,我们将这两个对象保存在一个数组中,并不断向数组中添加新的对象。随着时间的推移,这些对象将占用越来越多的内存,最终导致内存泄漏。

如何解决:

要避免这种情况,可以确保在不再需要对象时将其设置为 null,以便垃圾回收器可以释放这些对象。

function createCircularReference() {
  let objA = {};
  let objB = {};

  // 创建循环引用
  objA.self = objA;
  objB.self = objB;

  // 将 objA 和 objB 保存在一个数组中
  let objects = [objA, objB];

  // 模拟长时间运行的任务
  setInterval(() => {
    let newObj = {};
    objects.push(newObj);

    // 清理不再需要的对象
    if (objects.length > 10000) {
      objects.shift();
    }
  }, 1000);
}

createCircularReference();

在这个修改后的版本中,我们在数组中添加新对象的同时也清理掉一些旧对象,以防止内存无限增长。

回到顶部