LoginSignup
16
12

More than 5 years have passed since last update.

[ ] のほうが new Array(1000) より速いってホント?

Last updated at Posted at 2014-09-21

きっかけ

前回の記事を書くのために XSS の攻撃方法をいろいろ実験していたんだけど、同じ攻撃でもいろいろなスクリプトの挿入方法があることが分かったので、実行速度に差がないのか調べていたんですね。
それについては後日書くつもりなんですけど、JavaScript のパフォーマンスについてググっていたら、配列に 1000 個の要素を追加するときに [ ] で宣言する場合と、new Array(1000) で宣言する場合、[ ] のほうが V8 では2倍ほど速かったという記事を見つけてびっくりしました(゚д゚)

どういう実装にしたらそんなことが起こるんだろう?
C++ の std::vector だと、内部でバッファサイズが足りなくなると2倍の連続したメモリーを確保して、そちらへ丸ごとコピーする実装だったよね。
.NET Framework の List<T> クラスも同じような実装だったはず・・・。

Listクラスから抜粋
private void EnsureCapacity(int min) {
    if (_items.Length < min) {
        int newCapacity = _items.Length == 0? _defaultCapacity : _items.Length * 2;
        if ((uint)newCapacity > Array.MaxArrayLength) newCapacity = Array.MaxArrayLength;
        if (newCapacity < min) newCapacity = min;
        Capacity = newCapacity;
    }
}

やっぱり2倍に拡張してるよね。
そしたらサイズが大きくなるに従って連続したメモリー確保とコピーコストは跳ね上がっていくから、最初からサイズを渡せるならその方がいいはず。
.NET のメモリー管理をちゃんと勉強してないけど、マネージだとメモリー連続してなくてもよかったりするのかな?

JavaScript だとメモリー連続してなくてもよさそうだから、1つのバッファが極端に大きくならないように一定程度大きくなると別のバッファを確保して連続しているように見せるのかなぁ・・・。
どういう実装なのか想像がつかないわ(´・ω・`)

実験してみた

というわけで、本当なのか実験してみました。

テストコード
function test() {
    var run  = 100;
    var cnt  = 10000;
    var size = 10000000 / cnt;
    var msA  = 0;
    var msB  = 0;

    for (var i = 0; i < run; i++) {
        msA += testA(cnt, size);
        msB += testB(cnt, size);
    }
    console.log('A ' + (msA / run) + " ms");
    console.log('B ' + (msB / run) + " ms");

    function testA() {
        var startTime = new Date();
        for (var i = 0; i < cnt; i++) {
            var arr = [];
            for (var j = 0; j < size; j++) {
                arr[j] = 0;
            }
        }
        var endTime = new Date();
        return endTime - startTime;
    }

    function testB() {
        var startTime = new Date();
        for (var i = 0; i < cnt; i++) {
            var arr = new Array(size)
            for (var j = 0; j < size; j++) {
                arr[j] = 0;
            }
        }
        var endTime = new Date();
        return endTime - startTime;
    }
}

配列にゼロを1000万回代入して、それに掛かる時間を計測します。
それを100回実行した平均値を調べてみました。
cnt 変数の数字を大きくすると、小さな配列を何度も作って代入し、cnt 変数の数字を小さくすると、大きな配列を少ない回数作って代入するので、以下のような関係になります。
実行回数を合わせると時間掛かりすぎるので,こういう調べ方にしました(;´д`)

配列サイズ 10 100 1,000 10,000 100,000 1,000,000
実行回数 1,000,000 100,000 10,000 1,000 100 10

計測結果

[]-graph.png

new-array-graph.png

基本的に new Array(x) のほうが速いですね。
V8 の処理の仕方がかわったのかな?
Chrome と Opera は傾向が完全に一致していて、誤差レベルだけど Opera のほうがちょっとだけ速い。
でも配列サイズが10万になったとたんに、Chrome と Opera はパフォーマンスが極端に落ちていて、new Array(x) の方は IE と同レベルになっちゃいました。
よく使われるサイズで高速になるようにチューニングしたっぽいですね。

配列 10 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 656.67 42.80 78.98 41.29
new Array(x) 737.88 22.69 126.77 21.36

配列 100 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 633.71 48.32 89.79 45.60
new Array(x) 576.24 14.10 35.15 12.97

配列 1,000 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 612.07 41.73 117.06 38.99
new Array(x) 559.40 10.64 54.06 9.82

配列 10,000 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 619.40 43.41 76.83 41.22
new Array(x) 558.55 10.39 80.28 9.88

配列 100,000 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 625.12 42.16 70.14 39.25
new Array(x) 559.32 411.66 55.29 375.22

配列 1,000,000 個の場合

Internet
Explorer 11
Google
Chrome 37
Mozilla
Firefox 32
Opera 24
[ ] 646.35 153.36 67.02 132.58
new Array(x) 598.95 807.45 66.91 782.40

結論:お好きな方をどうぞ

どのブラウザでも配列のサイズが100~1000個のときが最速で、10個まで小さいと微妙にパフォーマンスが落ちています。
[ ] のほうが速かったケースは 10個のときの IE と Firefox、10万個以上のときの Chrome と Opera くらいかな。
配列を何度も作成する特殊なケースがあるなら、10000個以下なら new Array(x) がよさそうで、それ以上の個数なら [ ] がいい。

でも普通に配列をいくつか作って使う程度なら、ぶっちゃけどっちでも変わらないから好きな方を使ったらいいんじゃないかなぁ。
可読性とか、タイプ数とか、検索性とか、コード規約とか、置かれた状況と 個人的な好み で選択すればいいと思います (´∀`)

16
12
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
12