JavaScript:削除演算子はリークを作成します!?

こんにちは、ハブルナロド、陰湿なリークの歴史と、大きな誤解についてお話ししたいと思います。
実際、すべてが非常に単純です。 特定の条件下では、このような一見普通のコード行がリークを引き起こす可能性があります。
delete testedObject[ i ].obj; 

しかし、私は特定の条件でのみ繰り返します。 もう1つですが、これがブラウザーのバグなのか、JSの機能なのかはまだ不明です。
グーグルはこれについて何も言わなかった。ECMAScriptの仕様を掘り下げることも何も与えなかった。地味な状態では理解するのが難しいからだ。 実際、これがこの記事を書く理由でした。


先史時代


だから、私はある会社YのためにプロジェクトXに取り組み始めました。彼らは会社、従業員などのための管理システムをすべて1つのパッケージに必要としていました。 このビジネスはすべて、ブラウザを介して機能するはずです。 この奇跡をJSで書くことにしました。 アプリケーションの詳細は、タブを終日開いて、アクティブに使用できるようにすることです。 したがって、メモリの1キロバイトとプロセッサ時間の1ミリ秒ごとに戦いました。 フレームワークは実際にこのタスクに対応していなかったため、自分でバイクを作成する必要があり、奇跡が始まりました!

エッセンス


アプリケーションの完成した部分の次の部分の後、テストが開始されました。ああ、アプリケーションはゆっくりと記憶を食い尽くし、やめたくありません。 そして、例外なくすべてのブラウザで。 フォックスにとって最も致命的な結果であるため、タブを閉じることは役に立たず、メモリは消費されたままです。 最初は自転車で罪を犯しましたが、しばらくして真実の底に着き、すべてが削除演算子にあることに気付きました。

最初は、別のブラウザのバグを見つけて「幸せ」でした。 しかし、その後、私は疑いに苦しめられました。結局のところ、すべてのブラウザーの投票が流れるということはありえません。 はい。大規模なフレームワークでは、delete演算子が非常に積極的に使用されます。

そのため、私はJQueryのリークを妥協し始め、数時間苦しみましたが、リークはありませんでした。 何が問題なのか、JQueryコードを調べましたが、そこには魔法が見つかりませんでした。 さて、私は、新しいファイルを作成し、リークがある関数のプロトタイプを作成し、それでわいせつなものに対処し始めたと思った。

リークのある実際のプロトタイプコード
 <!DOCTYPE html> <html> <head> <title></title> <script type="text/javascript"> var count = 100000; var testedObject; function getObject() { //    return { first: { val : 'tratata', item : { val : 'tratata' } }, second: { val : 'tratata', item : { val : 'tratata' } }, third: { val : 'tratata', item : { val : 'tratata' } }, fourth: { val : 'tratata', item : { val : 'tratata' } }, fifth: { val : 'tratata', item : { val : 'tratata' } }, sixth: { val : 'tratata', item : { val : 'tratata' } }, seventh: { val : 'tratata', item : { val : 'tratata' } }, eighth: { val : 'tratata', item : { val : 'tratata' } }, ninth: { val : 'tratata', item : { val : 'tratata' } } }; } //   function fillArray() { testedObject = {}; for( var i = 0; i < count; i++ ) { testedObject[ i ] = { obj : getObject() }; } } //   function deleteObjects() { for( var i = 0; i < count; i++ ) { delete testedObject[ i ].obj; } } </script> </head> <body> <div> <button onclick="fillArray()" > </button> <button onclick="deleteObjects()" > </button> </div> </body> </html> 



リーク画面:


スクリーンショットは、オブジェクトの削除時に、何らかの理由でメモリが強く消費されるが、その後は以前の状態に解放されることを明確に示しています。 それでも、削除されたオブジェクトに割り当てられたメモリはクリアされませんでした。

同時に、delete演算子は非常に正常に動作し、誓いも叫びもせず、オブジェクトはそのまま削除され、すべては正常ですが、それらによって占有されているメモリは解放されません。

漏れでダウン


しばらくして、すべてが非常に単純であり、リークを回避できることに気付きましたが、コードを少し再構築する必要があります。
次のように実行すると、メモリがクリアされました。
 delete testedObject[ i ]; 


リークオプションなし
 <!DOCTYPE html> <html> <head> <title></title> <script type="text/javascript"> var count = 100000; var testedObject; function getObject() { //    return { first: { val : 'tratata', item : { val : 'tratata' } }, second: { val : 'tratata', item : { val : 'tratata' } }, third: { val : 'tratata', item : { val : 'tratata' } }, fourth: { val : 'tratata', item : { val : 'tratata' } }, fifth: { val : 'tratata', item : { val : 'tratata' } }, sixth: { val : 'tratata', item : { val : 'tratata' } }, seventh: { val : 'tratata', item : { val : 'tratata' } }, eighth: { val : 'tratata', item : { val : 'tratata' } }, ninth: { val : 'tratata', item : { val : 'tratata' } } }; } function fillArray() { testedObject = { obj : {} }; for( var i = 0; i < count; i++ ) { testedObject.obj[ i ] = getObject(); } } function deleteObjects() { for( var i = 0; i < count; i++ ) { delete testedObject.obj[ i ]; } } </script> </head> <body> <div> <button onclick="fillArray()" > </button> <button onclick="deleteObjects()" > </button> </div> </body> </html> 



もちろん、変更はそれほど複雑ではなく、私の自転車のアー​​キテクチャに大きな影響はありませんでしたが、最初のオプションがリークを引き起こしたことは非常に予想外で迷惑でした。

すぐに、リークの原因がスコープではなく、コンテキストではなく、インデックスではなく、パラメータ名ではないことを予約します。すべてチェックしました。

おわりに


だから、私は一種のリークを修正し、すべてが順調で、人生は良いです。 しかし、私はまだ多くの質問に苦しめられています。
関数の最初のバージョンと2番目のバージョンの根本的な違いは何ですか?
そして、それは機能またはブラウザのバグですか?
機能の場合、この機能がJSマナで説明されていないのはなぜですか?
ブラウザのバグの場合、何年も経ってまだ存在するのでしょうか?
誰かがすでにこれを知っているかもしれませんが、沈黙していますか?

私の記事が誰かの助けになることを願っています! そして、そのような漏れがないかバイクをチェックする価値があると思います!

PS:ご清聴ありがとうございました!!!

更新1:

これについては、これまでMozillaのバグトラッカーで書きましたが 、彼らの言うことを見てみましょう。

更新2:

トンネルの終わりのビーム



この巨大なmralephseriyPSのおかげで、コメントですべてが詳細に説明されています。 #comment_5107501#comment_5107585#comment_5107692も、 Mavimが私の特定のケースを詳細に説明しています。

すべての質問に対して明確な回答が寄せられました。これはJavaScriptの魔法でも、リークでも、ブラウザのバグでもありません。これは、削除演算子実装の機能です。 むしろ、それはメモリの過剰使用と呼ばれることがあり、私はちょうどそのような鉱山を踏みました。 しかし今、私たちは敵を直接知っており、問題なく彼を取り除きます。

みんなありがとう!

Source: https://habr.com/ru/post/J150723/


All Articles