如何在Javascript中清除内存?

32

var Obj = function(){}; var X = new Obj();

X = null能正确清除内存吗?

这样做是否等同?

var Obj = function(){}; 
var X   = {}; 
X.obj   = new Obj();
delete(X.obj);

编辑 尽管删除X.obj不会立即清除内存,但它会帮助垃圾收集。如果我不删除X.obj,则仍将存在指向对象的指针,因此GC可能不会清理它。

虽然我选择了@delnan的答案,但如果您正在阅读此文章,您也应该注意一下Benubird的文章。

我还注意到我最初错误地写成了delete(X)而不是delete(X.obj)- 抱歉。


您应该解释为什么对“清除内存”感兴趣。是为了减少 RAM 使用率吗?还是出于安全考虑?或是其他原因? - Ned Batchelder
为了减少RAM使用量/确保GC命中它 - Dave Stein
我喜欢这个问题。不幸的是,与大多数内存管理环境一样,最好的方法是让GC自己处理。哦,还要注意保留引用。 - Kris Krause
6个回答

25
简短的回答是你不需要这样做。delete仅仅是移除一个引用(并且不是像你尝试使用它的方式那样,参见上面的链接 - delete是一些人实际上很少理解的语言特性),仅此而已。实现会为您清除内存,但是它在何时清除(甚至是否清除,严格来说 - 这就是为什么不应该依赖提供它们的GC语言中的终结器)不是您的业务。请注意:
  • 只有可以证明对所有代码都无法访问的对象(即没有方法可以访问它)才能被删除。保留对谁的引用通常相当明显,至少在概念上是这样的。您只需要注意处理大量闭包时可能会捕获比您想象的更多的变量。还要注意,循环引用会被正确清除。
  • 旧版(但令人遗憾的是仍在使用)IE版本存在涉及JS事件处理程序和DOM元素的垃圾收集的错误。Google(甚至SO)应该有更好的关于我的记忆材料。
好的一面是,这意味着您将不会遇到悬空指针错误或(当然保存前述陷阱)内存泄漏。

在上面的代码示例中,由于没有任何指向它的东西,新的Obj()不会被垃圾回收机制从内存中移除吗? - Dave Stein
在第一个代码片段之后,创建的对象不再被引用,因此可以被回收。第二个代码片段误用了 delete(请参见Benubird的链接),结果取决于实现是否允许您删除变量,但如果允许,则不会有任何引用剩余。否则,只要 X 超出范围,对象就可以立即进行垃圾回收。无论哪种方式,内存都会在对象不再可达之后的某个时间点释放(除非是极小的机会,否则不会立即释放)。 - user395760
我刚刚注意到我的片段中有一个打字错误。我想要放置delete(X.obj)。那么,我应该做delete(X.obj)还是X.obj = null来加速GC? - Dave Stein
除非你已经证明引用保留时间过长存在问题(正如Kris Kause所说,GC本身工作得非常好),否则两者都不需要。如果存在这种情况,则两者同样适用 - 摆脱它就可以了,这才是最重要的。但是,处理 nullundefined 需要更多的代码,因此您可能想坚持使用其中之一。 - user395760
实际上我从来没有遇到需要将全局变量设置为null的情况...只是对象属性(例如如果我有一组对象并想要删除其中一个指针)。因此,实际上我可以继续使用delete(X.obj)。虽然这澄清了这两种情况的含义是好的。 - Dave Stein
@delnan,当您说“内存在某个时间点之后被释放(除非是极其偶然的情况下会立即释放)”时,您的意思是垃圾回收器不会在我们“删除”某个对象或将其设置为“null”时立即运行,而是根据某种算法定期运行吗?还是GC持续运行并等待对象被取消引用? - Vishal-L

13

2
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。仅有链接的答案如果链接页面发生更改可能会变得无效。 - Mistalis
@Mistalis,将其互联网档案馆的链接也包含在其中以供将来参考如何? - Benubird
2
@Benubird 请查看什么是仅链接答案? - Mistalis

4
不 - Javascript 在它自己感觉需要时运行垃圾回收。

4
Delete方法只会删除引用,而不是对象本身。其他引用将继续存在,等待垃圾回收器处理。
JavaScript 有自己的垃圾回收机制,当没有任何引用指向对象时,它会清理掉这些对象。
我仍然认为将对象设置为 null 是一个好的习惯。删除对象也有助于垃圾回收,因为它会发现某些东西悬空,然后说:“我要吃掉你,因为你孤零零的(接着就是一阵讽刺的笑声)”。
你应该看一下 在 JavaScript 中删除对象
尽管有垃圾回收机制,但你仍然需要确保脚本的性能得到优化,因为人们使用的计算机、浏览器和工具栏(以及数量)都会有所不同。

2
通常来说,Javascript中的内存管理是与用户代理相关的。垃圾回收的基础是通过引用计数。因此,通过将引用设置为null(使用delete关键字或显式赋值),您可以确保引用将被清除,前提是该对象没有任何超出其创建范围的引用。在这种情况下,GC已经清理了任何作用域结束的对象或变量,而无需您明确将其设置为null。
但是,需要注意一些事项-在JS中很容易创建循环引用,特别是在DOM元素和对象之间。必须小心清除(或首先不创建)对象内部与DOM元素相关的引用和/或从DOM元素引用的内容。如果确实创建了与DOM相关的to/from引用,请务必通过将引用设置为null来明确清除它们-既在您的对象上,也在DOM元素上。如果存在从子级到父级的引用,则仅将父对象设置为null是不够的,因为那些引用将继续存在,并且如果有任何从子对象到父对象的引用,那么父对象将因为那个引用而在内存中继续存在。
网页实际上可以通过这种方式泄漏内存垃圾-在您导航离开后,循环引用会使对象和DOM元素保留在内存中,直到您重启浏览器!
有关此主题的文章:http://docstore.mik.ua/orelly/webprog/jscript/ch11_03.htm,另一个详细查看:http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx

1

JavaScript内存的处理方式通常与Java类似 - 我的意思是,如果没有引用对象,就会有(或应该有)垃圾收集器删除它。因此,是的,简单地“将引用置空”是您应该“处理”释放内存的唯一方法,而真正的释放则是JS主机部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接