给一个字符串变量赋新值会产生需要回收的垃圾吗?

8
考虑以下 JavaScript 代码:

var s = "Some string";
s = "More string";

这种操作后,垃圾收集器(GC)是否还需要工作?
(我在思考尽量减少GC暂停时,是否应该担心分配字符串字面量。)
注:我对于需要最小化GC的要求已经明确表述,大家却都认为我是错的,这让我有点好笑。如果一定要知道详细情况:我有一个用javascript编写的游戏——它在Chrome中运行良好,但在Firefox中会出现间歇性的暂停,看起来似乎是由于GC引起的。(我甚至使用了Firefox的MemChaser扩展程序进行了检查,发现暂停恰好与垃圾回收同时发生。)

3
只有在出现严重的性能问题时才需要担心垃圾收集器,而对于几乎所有正常页面来说,这都是最不必担心的事情。 - Pointy
2
虽然我想知道答案(这就是为什么我没有提到上下文的原因),但在这种特定情况下,我正在尝试改进游戏引擎的性能。这几乎是您需要担心GC的典型情况。 - starwed
2
在项目早期了解GC的工作原理实际上是很好的,这样当您遇到问题时,就不会出现需要进行重大重构的情况 - 而且当您改变做事方式时,成本也更高。 - Jed Watson
@starwed - 你的问题非常基础,如果没有适当的上下文,GC几乎不值得担心。 如果你在原始问题中包含了游戏上下文和暂停观察,你会得到更严肃的关于GC的答案。 但是你问了一个没有上下文的基本问题,这就是为什么你得到了如此基本的答案。 你不应该对此感到有趣。 更具针对性的问题和更多的上下文将获得更有帮助的答案。 这在SO上始终如一。 - jfriend00
5个回答

10

是的,字符串需要进行垃圾回收,就像任何其他类型的动态分配对象一样。而且,这确实是一个合法的担忧,因为在繁忙的循环内部粗心地分配对象可能会导致性能问题。

然而,字符串值是不可变的(无法更改的),大多数现代JavaScript实现使用“字符串缓存”,也就是它们仅存储每个唯一字符串值的一个实例。这意味着,如果您有类似以下代码的东西...

 var s1 = "abc",
     s2 = "abc";

只会为 "abc" 的一个实例分配内存空间,这仅适用于字符串值,而不是 String 对象。

需要牢记的一些事情:

  1. substringslice 等函数每次调用时都会为其分配一个新对象(如果使用不同的参数调用)。

  2. 即使两个变量指向内存中相同的数据,当 GC 周期运行时仍然有两个变量需要处理。拥有过多的局部变量也会造成负面影响,因为每个变量都需要被 GC 处理,增加了额外开销。

关于编写高性能 JavaScript 的进一步阅读:


谢谢回答。(当然,我在搜索时已经遇到了这三个链接! :)) - starwed

0

是的,垃圾收集器将包含一个字符串对象“Some string”以消除。回答您的问题,在此字符串赋值将为GC带来工作。

由于字符串是不可变的并且经常被使用,JS引擎有一种处理它们的相当有效的方式。您不应该因为垃圾回收几个字符串而注意到任何暂停。垃圾回收器在正常的javascript编程过程中一直有工作要做。这就是它的工作原理。

如果您观察到GC导致的暂停,我很怀疑这是来自几个字符串的。更有可能出现更大的问题。无论您需要GC成千上万个对象或者进行一些非常复杂的任务,我们都不能在没有对整体代码进行研究之前进行推测。

除非您正在执行某些巨大的循环并且涉及数万个对象,否则这不应该是一个令人担忧的问题。在这种情况下,您可能希望编写更谨慎的程序,以最小化创建的中间对象数量。但是,在没有那个级别的对象的情况下,您应该首先编写清晰、可靠的代码,然后仅在某些事情向您展示存在性能问题需要担心时进行优化。


0

是的,但除非您正在循环执行数百万次,否则这可能不是您需要担心的因素。


0

正如您已经注意到的那样,JavaScript并不是JavaScript。它在不同的平台上运行,因此具有不同的性能特征。

因此,“在这种操作之后GC是否有工作要做?”这个问题的明确答案是:也许吧。如果脚本像你展示的那样简短,那么JIT编译器可能会完全删除第一个字符串。但是,在语言定义中没有规定必须是这样或者那样的规则。所以最终就像在JavaScript中经常发生的那样:你必须尝试一下。

更有趣的问题可能是:如何避免垃圾回收。方法是尽量减少新对象的分配。游戏通常具有相当恒定的对象数量,并且通常不会有新对象,直到旧对象变得无用。对于JS中的字符串来说,这可能更难,因为它们是不可变的。因此,尽可能使用其他(可变)表示替换字符串。


-2
回答你的问题“我在想是否应该担心在尝试最小化GC暂停时分配字符串字面量”的答案是:不需要。
实际上,关于垃圾收集方面,你真的不需要担心这种事情。
只有在创建和销毁大量JavaScript对象或大量DOM元素时,才需要考虑GC。

这不是正确的。字符串本身是不可变的。因此,“Some String”字符串是JS内存中的一个对象,当没有任何引用时,它必须由GC删除。 - jfriend00

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