[英]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 Shot
, Record Allocation Time
, Record Allocation Profile
来确定变量的内存状态。
看到
揭开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.