Chrome内存快照里怎么判断是不是内存泄漏?

W″可慧 阅读 12

我在用 Chrome DevTools 的 Memory 面板拍快照,但不太会看那些 retained size 和 distance,到底怎么看才能确定是不是真的内存泄漏了?

我试过反复打开关闭一个组件,按理说应该被回收,但快照里还是能看到很多 detached DOM tree,像这样:

function createModal() {
  const div = document.createElement('div');
  div.innerHTML = '<button>Close</button>';
  document.body.appendChild(div);
  div.querySelector('button').onclick = () => {
    document.body.removeChild(div);
  };
}

这种写法是不是会导致闭包引用没释放?该怎么分析?

我来解答 赞 2 收藏
二维码
手机扫码查看
1 条解答
程序员志鸣
判断内存泄漏就看一个指标:多拍几次快照,对比同一批对象的数量和size。如果只涨不跌,那就是泄漏了。

retained size 是关键,这个值表示这个对象以及它引用的所有东西总共占多少内存。distance 是到GC根的距离,距离越小越可疑,说明它很可能是泄漏链的源头。

你说的 detached DOM tree 就是典型问题。你那段代码确实有闭包泄漏:

function createModal() {
const div = document.createElement('div');
div.innerHTML = '<button>Close</button>';
document.body.appendChild(div);
div.querySelector('button').onclick = () => {
// 这个闭包引用了 div
document.body.removeChild(div);
};
}


点击关闭按钮后,div 虽然从 DOM 移除了,但 onclick 回调函数形成了一个闭包,这个闭包还持有着 div 的引用。事件处理器没清掉,对象就回收不掉。

怎么分析:

1. 在 Memory 面板拍下初始快照
2. 重复操作你的功能(比如打开关闭弹窗)十几次
3. 再拍一次快照
4. 选择第二个快照,切换到 Comparison 视图
5. 看 # Delta 列,正数的就是增长的对象

找到泄漏对象后,点进去看 Retainers 面板,一层层往上追,看是什么引用链保持着它。

修复办法:

function createModal() {
const div = document.createElement('div');
div.innerHTML = '<button>Close</button>';
document.body.appendChild(div);

const button = div.querySelector('button');
button.onclick = () => {
document.body.removeChild(div);
button.onclick = null; // 断开闭包引用
div.innerHTML = ''; // 清理内部元素引用
};
}


或者更彻底的做法是用 EventListener,并且确保在组件销毁时 removeEventListener。关键就是手动断开引用,让 GC 能回收。
点赞
2026-03-11 09:07