web-dev-qa-db-ja.com

Javascriptの文字列サイズの制限:私にとっては256 MB-すべてのブラウザで同じですか?

Javascriptで取得できる最大の文字列の長さに興味があったので、今日、Windows7で実行されているFirefox43.0.1で自分でテストしました。長さ2^28 - 1の文字列を作成できましたが、もう1文字の文字列を作成しようとしましたが、 Firebug "割り当てサイズのオーバーフロー"エラーが表示されました。これは、文字列が256MB未満である必要があることを意味します。 。

これはすべてのブラウザ、すべてのコンピュータ、すべての運用システムで同じですか、それとも状況によって異なりますか?

制限を見つけるために、次のスニペットを作成しました。

(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);
    }
})();

別のブラウザ/ OSを実行している場合は、結果を確認したいと思います。私の結果はでした。最大文字列長は268435455です。

PS:答えを探しましたが、最近見つけたトピックは2011年のものだったので、もっと最新のものを探しています。情報。

12
Pedro A

文字は16ビットで保存されます

256*2**20文字が文字列に含まれている場合、それは256メガバイトのメモリが割り当てられていることを意味するものではありません。 JavaScriptは、すべての文字を2バイトに格納します(仕様によってutf16でエンコードされているため)。

ロープ についての一言

今日のブラウザ(IEでさえ)は高度な方法で文字列を保存し、ほとんどの場合 ropedatastructure を使用します。

  • ロープを割り当てるためにコヒーレントメモリ領域は必要ありません
  • 部分文字列を重複排除することもできます。つまり、s+sは必ずしもsの2倍のメモリを使用するわけではありません。
  • 連結は非常に高速です
  • 要素へのアクセスは少し遅い

IEとChromeでいくつかの実行を調べると、どちらも文字列の遅延評価を使用し、ときどき展開しようとします。次のスニペットを実行した後、どのブラウザも実行されませんでした。以前よりも多くのメモリを使用しましたが、コンソールに保存されているwindow.LONGEST_STRINGを操作しようとすると、IEメモリ不足エラーがスローされ、chrome =短時間フリーズし、大量のメモリ(> 2 GB)を消費しました。

ps:私のラップトップではIE11の最大文字列サイズは4 GBでした、Chromeは512MBでした

ブラウザの動作

IE11

IE11

Chrome47

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);
12
Tamas Hegedus

内部実装では、UCS2またはUTF16のいずれかを使用できます。 @hege_hegedusが示唆しているように、少なくともFirefoxはRope構造を使用します( https://dxr.mozilla.org/mozilla-central/search?q=%2Btype-ref%3ARopeBuilder )。コードは私に以下の結果を与えます:

クロームバージョン39.0.2171.95OSバージョンLinux:3.13.0-43-汎用

Firefox 34.0

Chrome出力(@@ hege_hegedusコードから):最大文字列長は次のとおりです:268435440文字536870880バイト511.9999694824219メガバイト最長の文字列を格納する最初の文字を読み取ろうとするa最後の文字を読み取ろうとするa長さを読み取ろうとする268435440

Firefoxの出力(OPコードから):「最大文字列長は268435455です」

http://gpupowered.org/string_js.txt にアーカイブ

1
Prabindh

バグレポート クロムトラッカーのコメントは次のとおりです。

_... 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年のものであることに注意してください。前のリンクは、toString()の制限に達したNodeJSツールに関するものであるため、現在のバージョンのV8ではまだ 結果 であると思います。

1
Jason