清理不再引用且从未添加到文档中的元素
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化。可以使<canvas>
元素不再被引用或,方法是将任何引用它的变量设置为null
或其他变量,或(唯一)引用它的变量超出作用域。
当然还有另一种情况与变量的内存管理有关,那就是闭包。只要被封闭的函数"在作用域中"(换句话说,有东西引用它),被封闭的变量就会继续占用(少量)内存。这样一个变量的值——无论是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
来确定变量的内存状态。
- 如何检测在JavaScript触发垃圾收集的内存分配? <
- 记忆术语/gh>
如何记录堆快照
发现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
下的整棵树是GC的候选。内存管理
如果没有其他对canvas
的引用,它应该被垃圾收集。
首先,有一个很大的警告,即不是每个实现都使用相同的垃圾收集算法,因为它还没有标准化。即旧版本的IE。
引用MDN文档:
众所周知,Internet Explorer 6和7存在引用计数垃圾DOM对象的收集器然而,大多数现代浏览器使用标记-清除垃圾收集:
截至2012年,所有现代浏览器都提供了标记和清除功能垃圾收集器。JavaScript领域的所有改进垃圾收集(分代/增量/并发/并行)垃圾收集)在过去的几年里都实现了改进了这个算法,但没有改进垃圾集合算法本身也不是其约简的定义当"一个对象不再需要"时。
标记-扫描将在不可达时删除对象。因此,在您的示例中,如果为canvas
变量赋一个新值,则新创建的元素将不可达,并被标记为垃圾收集。它可能会占用一小段时间的内存,直到垃圾收集器运行。另外,由于您使用了let
,一旦内存中不再需要它所在的块作用域,它可能会被垃圾收集。
好吧,我现在可以给你一个有价值的答案,因为我已经亲自检查过了。在您的示例中,您刚刚创建了一个新变量并将其值设置为document.createElement('canvas')
。
在决定将该变量追加到DOM之前,它只不过是存储在变量中的一个值。通过将值设置为null,变量现在被存储,并将内存作为一个普通的、单个的空变量。
如果你把它附加到你的文档中,情况就完全相反了。如果将变量的值设置为null,元素就不会被删除,否则会浪费内存。
- Firefox:点击并更改未附加到文档树中的复选框元素上的事件
- 将事件侦听器添加到文档,而不是签入元素存在,然后添加事件侦听器
- 用于修改文档元素的 PHP 代码
- 如何切换文档元素的可见性
- HTTP 获取节点 JS 以使用文档元素进行解析
- 检票口 - 使用 AJAX 刷新组件 - 文档元素后的垃圾
- 按位置访问文档元素时检测数组
- 这是将两个文档元素的数组添加到一个数组中的最佳方法
- 获取 0 的文档元素返回什么
- scrollTop为javascript中的所有文档元素返回0,但滚动事件在body标记上触发
- 文档元素Firefox之后的垃圾使用JQuery Get加载内容时出错
- 使用Javascript文档元素区分不同的浏览器
- rails布局文件中的Javascript文档元素
- Onclick文档元素永久禁用
- 向html表中添加xml文档元素
- 文档元素的模拟对象
- 将文档元素's innerHTML设置为长字符串
- 用javascript创建的文档元素的范围
- Firefox 和 AJAX Junk 之后的文档元素
- 如何从通过外部.js脚本标记创建的 iframe 授予功能或文档元素的权限