typeof nullの値がループ内で変化するのはなぜですか?


109

Chromeコンソールでこのスニペットを実行する:

function foo() {
    return typeof null === 'undefined';
}
for(var i = 0; i < 1000; i++) console.log(foo());

1000回印刷する必要がありますfalseが、一部のマシンでは、いくつかfalseの反復で印刷され、その後true残りの印刷が繰り返されます。

ここに画像の説明を入力してください

なぜこうなった?それは単なるバグですか?


4
それは...私にとって真の1000倍を返す
ホアンロング

2
バグだと思います。262が偽/ 738が真です
Jax Tellerが

1
これはchromeのコンソールでは奇妙なことです。配列にプッシュしてログを記録すると、それはすべてfalseです。そのままでは、trues の数はChromeで変動します。
dandavis

1
@HoàngLongは、質問で述べたように、一部のマシンでのみ発生します。一部のバージョンのChromeでのみ発生する可能性もあります
Agos

2
@HoàngLong必ずChromeでそれを実行している作る
のび太

回答:


74

このために開いているクロムのバグがあります:

問題604033-JITコンパイラーがメソッドの動作を保持しない

だからはいそれは単なるバグです!


5
「ただ」?これは世界中の任意のWebアプリケーションを壊すことができませんでしたか?
jpmc26 2016年

6
「ただ」というのは、それが特徴や奇妙なことではないということです。重大なバグですが、単なるバグです!
Slumber86 2016年

37

これは実際にはV8 JavaScriptエンジン(Wiki)のバグです。

このエンジンは、Chromium、Maxthron、Android OS、Node.jsなどで使用されています。

このRedditトピックで見つけることができる比較的単純なバグの説明

最新のJavaScriptエンジンは、実行時にJSコ​​ードを最適化されたマシンコードにコンパイル(ジャストインタイムコンパイル)して、より高速に実行します。ただし、最適化ステップには、長期的なスピードアップと引き換えに初期パフォーマンスコストがいくらかあるため、エンジンは、メソッドの使用頻度に応じて、メソッドがそれに値するかどうかを動的に決定します。

この場合、最適化されたパスにのみバグがあるように見えますが、最適化されていないパスは正常に機能します。したがって、最初はメソッドは意図したとおりに機能しますが、ループ内で頻繁に呼び出されると、エンジンはある時点でそれを最適化してバグのあるバージョンに置き換えます。

このバグは、V8自体(commit)、およびChromium(バグレポート)およびNodeJS(commit)で修正されたようです。


私はバグがNode.js 6.2.2にまだあることを確認しました。
Michael Shopsin

それは今日(21.06)V8エンジンで修正されました、私はすぐに関連するソフトウェアが更新されると思います。
セルゲイ

Node.js 6.2.xへのv8修正のバックポートは、TheAlphaNerdが所有する問題#7348としてすでに進行中です
Michael Shopsin

18

なぜ変更されるかという直接的な質問に答えるために、このバグはChromeで使用されるV8 JSエンジンの「JIT」最適化ルーチンにあります。最初は、コードは記述されたとおりに実行されますが、実行すればするほど、最適化の利点が分析コストを上回る可能性が高まります。

この場合、ループで繰り返し実行された後、JITコンパイラは関数を分析し、最適化されたバージョンに置き換えます。残念ながら、分析では誤った仮定が行われ、最適化されたバージョンでは実際には正しい結果が生成されません。

具体的には、RedditユーザーのRainHappensは型の伝播のエラーであると示唆しています。

また、型の伝播も行います(変数などの型の場合と同様)。変数が未定義またはnullの場合の特別な「検出不可能な」タイプがあります。この場合、オプティマイザは「nullは検出不可能」になるため、比較のために「未定義」の文字列に置き換えることができます。

これは、コードを最適化する際の難しい問題の1つです。パフォーマンスのために再配置されたコードが元のコードと同じ効果を持つことを保証する方法。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.