假设我创建了一个新元素:
let canvas = document.createElement('canvas');
现在,稍后在脚本中,我删除了对它的任何JS引用。
canvas = null;
画布元素本身是否仍然存在,占用内存?或者它会像任何其他未引用的对象一样被垃圾收集?请注意,我还没有将其添加到文档中。
答案 0 :(得分:5)
<canvas>
元素本身是否仍然存在,记忆?或者它会像其他任何未引用的对象一样被垃圾收集吗?
是的,它暂时仍然存在。是的,它将在适当的时候进行垃圾收集。
其他海报似乎对canvas
变量与<canvas>
元素之间GC行为的差异略有混淆。变量在堆栈上分配,而不是堆。只要它们在范围内,它们就会占用堆栈上的少量内存。由于处于调用链中,它们仍然在范围内。退出函数并弹出堆栈帧时,将释放它们使用的内存。
元素与其他对象一样,在堆上分配,并进行垃圾回收。当不再引用时,它们是GC'd。通过将引用它的任何变量设置为<canvas>
或其他内容,或,可以使null
元素不再被引用 ( only)变量指的是超出范围。
当然还有一个与变量的内存管理有关的案例,即闭包。只要封闭的函数是“在范围内”,换句话说,某个引用它的东西,一个被关闭的变量继续占用(少量)内存。这个变量的值 - 无论是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(最终)。
底线是您无需担心任何此类问题。它只是有效,除非是病理情况或引擎错误。
答案 1 :(得分:2)
您可以在Take Heap Shot
的{{1}}标签处使用Record Allocation Time
,Record Allocation Profile
,Profiles
来确定变量的内存状态。
见
揭露DOM泄漏
堆分析器具有反映双向的能力 浏览器本机对象(DOM节点,CSS规则)和之间的依赖关系 JavaScript对象。这有助于发现其他不可见的泄漏 由于被遗忘的独立DOM子树浮动而发生。
DOM泄漏可能比您想象的要大。请考虑以下示例 - 何时是#tree GC?
DevTools
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
维护对它的父(parentNode)的引用,并递归到#leaf
,所以只有当leafRef无效时才是#tree
下的整个树,GC的候选者。
如果没有对#tree
的其他引用,则应该进行垃圾回收。您可以通过检查堆快照来确定这一点。
答案 2 :(得分:2)
首先,有一个很大的警告,并非每个实现都使用相同的垃圾收集算法,因为它尚未标准化。即,IE的旧版本。
已知Internet Explorer 6和7具有引用计数垃圾 DOM对象的收集器
但是,大多数现代浏览器都使用标记和扫描垃圾回收:
截至2012年,所有现代浏览器都进行了标记和扫描 垃圾收集器即可。 JavaScript领域的所有改进 垃圾收集(世代/增量/并发/并行) 垃圾收集)在过去几年是实施 这种算法的改进,但没有改进垃圾 收集算法本身也没有减少其定义 当“不再需要一个物体”时。
Mark-and-Sweep会在无法访问时移除对象。因此,在您的情况下,如果为canvas
变量分配新值,则新创建的元素将无法访问并标记为垃圾回收。它可能占用内存很短的时间,直到垃圾收集器运行。此外,由于您使用了let
,因此只要内存中不再需要block scope it's located in,就可能会对其进行垃圾回收。
答案 3 :(得分:1)
document.createElement('canvas')
。
在您决定将该变量附加到DOM中之前,它只不过是存储在变量中的值。通过将值设置为null,现在存储变量并将内存作为普通的单个空变量。
如果您将其附加到您的文档中,情况将完全相反。通过将变量的值设置为null,该元素不会被删除,然后会浪费内存。