Javascript 字符串大小限制:对我来说是 256 MB - 所有浏览器都一样吗?

Posted

技术标签:

【中文标题】Javascript 字符串大小限制:对我来说是 256 MB - 所有浏览器都一样吗?【英文标题】:Javascript string size limit: 256 MB for me - is it the same for all browsers? 【发布时间】:2016-04-29 17:07:27 【问题描述】:

很好奇我可以在 javascript 中获得的最大字符串长度是多少,我今天在我的 Firefox 43.0.1 上进行了测试,在 Windows 7 中运行。我能够构造一个长度为 2^28 - 1 的字符串,但是当我尝试创建一个带有多个字符的字符串时,Firebug 向我显示了 “分配大小溢出” 错误,这意味着该字符串必须小于 256 MB。

这对于所有浏览器、所有计算机、所有操作系统都是一样的,还是视情况而定?

我创建了以下 sn-p 来找出限制:

(function() 
    strings = ["z"];
    try 
        while(true) 
            strings.push(strings[strings.length - 1] + strings[strings.length - 1]);
        
     catch(err) 
        var k = strings.length - 2;
        while(k >= 0) 
            try 
                strings.push(strings[strings.length - 1] + strings[k]);
                k--;
             catch(err) 
        
        console.log("The maximum string length is " + strings[strings.length - 1].length);
    
)();

如果您运行的是不同的浏览器/操作系统,我想看看您的结果。我的结果是最大字符串长度为 268435455

P.S.:我四处寻找答案,但我发现的最新主题是 2011 年的,所以我正在寻找更新的信息。

【问题讨论】:

当我在 Ubuntu 15.10 上的 Firefox 45.0a2 中尝试 "a".repeat(268435456) 时,我得到“RangeError: repeat count must be less than infinity and not overflow maximum string size”。 ecma-international.org/ecma-262/6.0/… 引用 here 中的 Douglas Crockford。 ECMAScript 编程语言规范没有指定最大长度。最大长度将是特定于实现的。对于某些实现,它是可用内存的函数,但如果可移植性很重要,则不应依赖它。 由于字符串是每个字符 16 位,因此 250 MB 字符的字符串使用 500 MB 内存。从表面上看,字符串大小的限制可能与blob大小的限制相同@hege_hegedus @noob 上面链接的 ES6 规范说最大值是 2^53-1 个字符。克罗克福德的反应已有 10 多年的历史了。 【参考方案1】:

字符存储在 16 位中

当您看到256*2**20 字符在字符串中时,这并不意味着分配了 256 兆字节的内存。 JavaScript 将每个字符存储在两个字节上(因为它是由规范编码的 utf16)。

关于ropes

如今的浏览器(甚至 IE)以高级方式存储字符串,最常见的是使用 rope datastructure。

绳索不需要分配一致的内存区域 甚至可以对子字符串进行去重,这意味着s+s 不一定使用两倍于s 的内存 连接速度非常快 元素访问有点慢

通过检查 IE 和 Chrome 中的一些运行,我想说它们都对字符串使用了一些惰性求值,并且偶尔会尝试扩展它们。运行以下 sn -p 后,没有一个浏览器使用比以前更多的内存。但是如果我尝试在控制台中操作存储的window.LONGEST_STRING,IE会抛出内存不足的错误,并且chrome会在短时间内冻结,并消耗大量内存(> 2 GB)。

ps:在我的笔记本电脑上,IE11 的最大字符串大小为 4 GB,Chrome 为 512 MB

浏览器行为

IE11

Chrome47

确定最大字符串大小的更快算法

var real_console_log = console.log;
console.log = function(x) 
  real_console_log.apply(console, arguments);
  var d = document,b=d.body,p=d.createElement('pre');
  p.style.margin = "0";
  p.appendChild(d.createTextNode(''+x));
  b.appendChild(p);
  window.scrollTo(0, b.scrollHeight);
;


function alloc(x) 
    if (x < 1) return '';
    var halfi = Math.floor(x/2);
    var half = alloc(halfi);
    return 2*halfi < x ? half + half + 'a' : half + half;


function test(x) 
    try 
        return alloc(x);
     catch (e) 
        return null;
    


function binsearch(predicateGreaterThan, min, max) 
    while (max > min) 
        var mid = Math.floor((max + min) / 2);
        var val = predicateGreaterThan(mid);
        if (val) 
            min = mid + 1;
         else 
            max = mid;
        
    
    return max;


var maxStrLen = binsearch(test, 10, Math.pow(2, 52)) - 1;
console.log('Max string length is:');
console.log(maxStrLen + ' characters');
console.log(2*maxStrLen + ' bytes');
console.log(2*maxStrLen/1024/1024 + ' megabytes');
console.log('');
console.log('Store longest string');
window.LONGEST_STRING = alloc(maxStrLen);

console.log('Try to read first char');
console.log(window.LONGEST_STRING.charAt(0));
console.log('Try to read last char');
console.log(window.LONGEST_STRING.charAt(maxStrLen - 1));
console.log('Try to read length');
console.log(window.LONGEST_STRING.length);

【讨论】:

奇怪的是,您在 Chrome47 上的最大长度仅比我的限制少 15 个字符,我原以为差异与 2 的幂有关...非常感谢! @Hamsteriffic 如果最大大小取决于连接子字符串的大小,我不会感到惊讶。【参考方案2】:

铬跟踪器的bug report 有这样的评论:

... When allocation fails, we create a 
Failure pointer encoding the amount requested, as well as some tag and 
type bits. This puts a limit on the maximally possible allocation 
request in 32-bit versions of 2^27-1. The maximal flat string length is 
~2^28 (512MB space), and the maximal string length is 2^29-1...

请注意,这是从 2009 年开始的,所以我想在当前版本的 V8 中这仍然有 consequences,因为之前的链接是关于一个 NodeJS 工具运行到 toString() 的限制。

【讨论】:

【参考方案3】:

内部实现可以使用 UCS2 或 UTF16。正如@hege_hegedus 建议的那样,至少 Firefox 使用 Rope 结构(https://dxr.mozilla.org/mozilla-central/search?q=%2Btype-ref%3ARopeBuilder)。代码给了我以下结果:

Chrome 版本 39.0.2171.95 操作系统版本 Linux:3.13.0-43-通用

火狐 34.0

Chrome 输出(来自@@hege_hegedus 代码): 最大字符串长度为: 268435440 个字符 536870880 字节 511.9999694824219 兆字节 存储最长的字符串 尝试阅读第一个字符 一种 尝试阅读最后一个字符 一种 尝试读取长度 268435440

Firefox 输出(来自 OP 代码): "最大字符串长度为268435455"

存档于http://gpupowered.org/string_js.txt

【讨论】:

以上是关于Javascript 字符串大小限制:对我来说是 256 MB - 所有浏览器都一样吗?的主要内容,如果未能解决你的问题,请参考以下文章

这个例子应该如何工作?它对我来说是错误的

具有强类型和无大小限制的轻量级 SQL 数据库

如何在搜索时限制异步显示的结果?

Mongodb 设计,嵌入与关系

增加 qtreewidget 的大小

模板专业化结构大小