繁体   English   中英

清除不再引用的元素,并且从未添加到文档中

[英]Clean-up of elements that are no longer referenced, and were never added to the document

假设我创建了一个新元素:

let canvas = document.createElement('canvas');

现在,稍后在脚本中,我删除任何JS引用。

canvas = null;

canvas 元素本身是否仍然存在,记忆? 或者它会像任何其他未引用的对象一样被垃圾收集? 请注意,我实际上没有将其添加到文档中。

<canvas>元素本身是否仍然存在,占用内存? 或者它会像任何其他未引用的对象一样被垃圾收集?

是的,它暂时仍然存在。 是的,它会在适当的时候收集垃圾。

其他海报似乎对canvas 变量<canvas> 元素之间GC行为的差异略有混淆。 变量在堆栈上分配,而不是堆。 只要它们在范围内,它们就会占用堆栈上的少量内存。 由于处于调用链中,它们仍然在范围内。 退出函数并弹出堆栈帧时,将释放它们使用的内存。

与其他对象一样,元素在堆上分配,并受垃圾回收的限制。 当不再引用时,它们是GC'd。 可以通过将引用它的任何变量设置为null或其他东西, 或者引用它的(仅)变量超出范围,使<canvas>元素不再被引用。

当然还有一个与变量的内存管理有关的案例,即闭包。 只要封闭的函数是“在范围内”,换句话说,某个引用它的东西,一个被关闭的变量继续占用(少量)内存。 这个变量的值 - 无论是DOM元素还是JS对象还是其他任何东西 - 在闭包中的函数超出范围之前不会也不能进行GC。 小例子:

function a() {
  const div = document.createElement('div');
  return function() {
    console.log(div);
  };
}

function b() {
  const func = a();
}

输入b ,将在堆栈上为func分配存储空间。 a被调用,它创建的DOM元素并返回内部函数。 此时, div仍然被分配,因为它已被关闭并从内部函数中引用。 DOM元素保留在堆中。 一旦b退出,变量func就会从堆栈框架中弹出,这意味着任何时候都不会引用闭包函数。 这意味着div不再适用范围。 这反过来意味着该元素不再被引用,并且将被GC(最终)。

最重要的是,您无需担心任何此类问题。 它只是工作,除了病态案例或引擎错误。

您可以在DevTools Profiles选项卡上使用Take Heap ShotRecord Allocation TimeRecord Allocation Profile来确定变量的内存状态。

看到

  • 如何检测在JavaScript中触发垃圾收集的内存分配?
  • 记忆术语
  • 如何记录堆快照

    揭开DOM漏洞

    堆分析器能够反映浏览器本机对象(DOM节点,CSS规则)和JavaScript对象之间的双向依赖关系。 这有助于发现由于遗忘的分离的DOM子树浮动而发生的其他隐形泄漏。

    DOM泄漏可能比您想象的要大。 请考虑以下示例 - #tree GC何时?

      var select = document.querySelector; var treeRef = select("#tree"); var leafRef = select("#leaf"); var body = select("body"); body.removeChild(treeRef); //#tree can't be GC yet due to treeRef treeRef = null; //#tree can't be GC yet due to indirect //reference from leafRef leafRef = null; //#NOW can be #tree GC 

    #leaf维护对它的父(parentNode)的引用,并递归到#tree ,所以只有当leafRef无效时,#tree下的#tree#tree GC的候选者。

  • 内存管理

如果没有其他对canvas引用,则应该进行垃圾回收。 您可以通过检查堆快照来确定这一点。

首先,有一个很大的警告,即并非每个实现都使用相同的垃圾收集算法,因为它尚未标准化。 即,IE的旧版本。

引用MDN文档

已知Internet Explorer 6和7具有用于DOM对象的引用计数垃圾收集器

但是,大多数现代浏览器都使用标记和清除垃圾回收:

截至2012年,所有现代浏览器都提供了标记 - 清除垃圾收集器 在过去几年中,在JavaScript垃圾收集(生成/增量/并发/并行垃圾收集)领域所做的所有改进都是对该算法的实现改进,但不是对垃圾收集算法本身的改进,也没有减少对时间的定义。 “不再需要一个物体”。

Mark-and-Sweep将在无法访问时删除对象。 因此,在您的情况下,如果为canvas变量分配新值,则新创建的元素将无法访问并被标记为垃圾回收。 它可能占用内存很短的时间,直到垃圾收集器运行。 此外,因为你使用let这可能是尽快收集垃圾块范围它位于内存中不再需要。

哦,我现在可以给你一个有价值的答案,因为我自己检查了一下。 在您的情况下,您刚刚创建了一个新变量并将其值设置为document.createElement('canvas')

在您决定将该变量附加到DOM中之前,它只不过是存储在变量中的值。 通过将值设置为null,现在存储变量并将内存作为普通的单个空变量。

如果您将其附加到您的文档中,情况将完全相反。 通过将变量的值设置为null,不仅可以删除该元素,而且会浪费内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM