用Firefox处理大字符串比Chrome快约9000倍:为什么?

20

基准测试:http://jsperf.com/substringing

所以,我正在启动我的第一个基于HTML5的客户端项目。它将需要将非常大的文本文件解析为对象数组或数组的形式。我知道如何编写代码; 我现在主要关注的是尽可能快地获取解析器代码,并且我的主要测试平台是Chrome。然而,在查看子字符串方法之间的差异时(我很长时间没有接触JavaScript了),我注意到这个基准测试在Chrome中比FireFox慢得多。为什么?

我的第一个假设是与FireFox的JS引擎处理字符串对象的方式有关,对于FireFox,这个操作只是简单的指针操作,而对于Chrome来说,它实际上正在进行硬拷贝。但是,我不确定为什么Chrome不会进行指针操作,也不知道为什么FireFox会进行指针操作。有人有一些见解吗?

JSPerf似乎在浏览器范围上抛出了我的FireFox结果,没有显示它们。对我来说,在FF4上.substr()上我得到9,568,203±1.44%Ops/sec。

编辑:我看到下面有一个FF3.5的性能结果实际上低于Chrome。所以我决定测试我的指针假设。这使我到达了Substrings测试的第二个修订版本,在其中FF4中执行1,092,718±1.62%次/秒,而Chrome中仅执行1,195±3.81%次/秒,只快1000倍,但仍存在无法解释的性能差异。

附言:不,我一点也不关心Internet Explorer。我关心的是尝试提高我的技能并更深入地了解这种语言。


4
链接在页面顶部的标题中。或者呢? - MischaNix
1
我在Chrome 11中看到约1.1k/s,在FF3.6中看到约250/s。 - CanSpice
@MischaNix请获取Chrome 13的副本,看看瓶颈是否消失。 - Raynos
只是一个想法,如果你必须要使用子字符串,并且这个程序的最终结果必须在用户PC上运行,而数据集的大小是任意的,那么有没有更好的方法来表示你的数据?也许可以使用XML或JSON? - Russ Clarke
1
你可以尝试将其解析为流,同时不使用任何子字符串类型函数...如果在字段开头有一个标记,只需将每个字符附加到变量中,直到达到字段的末尾。该变量将包含整个字段,而无需使用子字符串方法。相比之下,将字符附加到变量应该非常快速。 - Justin808
显示剩余6条评论
2个回答

17
在SpiderMonkey(Firefox中的JS引擎)中,substring()调用只会创建一个新的“依赖字符串”:一个存储其所属子字符串、起始和结束偏移量指针的字符串对象。这样做是为了使substring()快速,并且鉴于不可变字符串,这是一种明显的优化。
至于为什么V8不这样做...可能是因为V8试图节省空间:在依赖字符串设置中,如果你持有子字符串但忘记原始字符串,原始字符串无法被GC回收,因为子字符串正在使用它的一部分字符串数据。
无论如何,我刚刚看了一下V8源代码,它似乎根本不使用任何形式的依赖字符串;尽管注释没有解释他们为什么不这样做。
[更新,2013年12月]:正如Paul Draper指出的那样,在我提供上述答案几个月后,V8增加了对依赖字符串的支持。

这个答案是不正确的,V8确实有依赖字符串。甚至还有一个V8 bug关于这个问题,它会导致小字符串占用大量内存。 - Paul Draper
V8在2011年8月左右添加了依赖字符串。请参见https://codereview.chromium.org/7477045/。因此,事实上,在给出答案时是正确的。如果您尝试在原始问题中使用当前版本的Chrome进行测试,它的行为与当时的Chrome完全不同。 - Boris Zbarsky

1
你在基准测试结果中排除了对 .length 的读取吗?
我相信 V8 有几种字符串的表示形式:
1. a sequence of ASCII bytes
2. a sequence of UTF-16 code units.
3. a slice of a string (result of substring)
4. a concatenation of two strings.

数字4是使字符串+=高效的原因。

我只是猜测,但如果他们试图将两个字符串指针和一个长度打包到一个小空间中,他们可能无法使用指针缓存大长度,因此可能最终遍历连接的链表以计算长度。当然,这假设Array.prototype.join从数组部分创建形式为(4)的字符串。

它确实导致了一个可测试的假设,即使没有缓冲区复制也可以解释差异。

编辑:

我查看了V8源代码,StringBuilderConcat是我开始提取的地方,特别是runtime.cc


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