ホームページ ウェブフロントエンド jsチュートリアル me_javascript スキルから JScript のバグとメモリ管理を学ぶ

me_javascript スキルから JScript のバグとメモリ管理を学ぶ

May 16, 2016 pm 03:31 PM
bug jscript メモリ管理

1. JScript のバグ

IE の JScript の ECMAScript 実装は、名前付き関数式に深刻な混乱をもたらし、多くの人が名前付き関数式に反対しており、現在も使用されているバージョン (IE8 で使用されているバージョン 5.8) さえも存在しています。次のような質問があります。

IE が実装時に犯した間違いを見てみましょう。よく言われるように、敵を知ることによってのみ無敵になれます。次の例を見てみましょう:

例 1: 外部スコープに漏洩した関数式の識別子

var f = function g(){};
typeof g; // "function"
ログイン後にコピー

名前付き関数式の識別子は外部スコープでは無効であると前述しましたが、JScript は明らかにこの仕様に違反しています。上記の例の識別子 g は関数オブジェクトに解析されますが、これは非常に複雑です。 -to-find バグはこの理由によって発生します。

注: この問題は IE9 で修正されたようです

例 2: 名前付き関数式を関数宣言と関数式の両方として扱います

typeof g; // "function"
var f = function g(){};
ログイン後にコピー

フィーチャー環境では、関数宣言は式の前に解析されます。上記の例は、JScript が実際の宣言の前に g を解析するため、名前付き関数式を実際に関数宣言として扱うことを示しています。

この例は次の例につながります。

例 3: 名前付き関数式は、2 つのまったく異なる関数オブジェクトを作成します。

var f = function g(){};
f === g; // false
f.expando = 'foo';
g.expando; // undefined
ログイン後にコピー

これを見ると、どのオブジェクトを変更しても他のオブジェクトは変更されないため、誰もが問題は深刻であると考えるでしょう。この例では、2 つの異なるオブジェクトを作成することがわかります。つまり、f の属性を変更して特定の情報を保存し、それを当然のことながら、g の同じ name 属性を参照して使用する場合です。同じオブジェクトの場合、それはまったく不可能であるため、大きな問題が発生します。

もう少し複雑な例を見てみましょう:

例 4: 関数宣言のみを順番に解析し、条件付きステートメント ブロックを無視します

var f = function g() {
  return 1;
};
if (false) {
 f = function g(){
 return 2;
 };
}
g(); // 2
ログイン後にコピー

このバグは見つけるのが非常に困難ですが、バグの原因は非常に単純です。まず、g は関数宣言として解析されます。JScript の関数宣言は条件付きコード ブロックの対象ではないため、この厄介な if 分岐では、g は別の関数 function g(){ return 2 } として扱われ、再度宣言されただけです。 。次に、すべての「正規」表現が評価され、新しく作成された別のオブジェクトへの参照が f に与えられます。式が評価されるときに忌まわしい if 分岐 "" が入力されることはないため、 f は最初の関数 function g(){ return 1 } を参照し続けます。これを分析すると、問題は非常に明確になります。十分注意して f で g を呼び出すと、無関係な g 関数オブジェクトが

と呼ばれます。

arguments.callee を使用してさまざまなオブジェクトを比較した場合の違いは何なのかと疑問に思われるかもしれません。見てみましょう:

var f = function g(){
  return [
  arguments.callee == f,
  arguments.callee == g
  ];
};
f(); // [true, false]
g(); // [false, true]
ログイン後にコピー

ご覧のとおり、arguments.callee の参照は常に呼び出される関数です。これは、後で説明するように、実際には良いことです。

もう 1 つの興味深い例は、宣言を含まない代入ステートメントで名前付き関数式を使用することです。

(function(){
 f = function f(){};
})();
ログイン後にコピー

コード分析によると、最初はグローバル属性 f を作成する必要がありました (名前付き宣言を使用する一般的な匿名関数と混同しないように注意してください)。まず、式が変更されました。式は関数宣言として解析されるため、左側の f はローカル変数として宣言されます (一般的な無名関数の宣言と同じ)。関​​数が実行されるときには、f はすでに定義されており、関数 f( ) 右側の {} はローカル変数 f に直接割り当てられているため、f はグローバル属性ではありません。

JScript がいかに異常であるかを理解した後、まず、識別子が外部スコープに漏洩しないようにする必要があります。次に、関数名として使用される識別子を引用符で囲んではなりません。グラム? ——gが存在しないふりをすることができれば、どれだけ無用なトラブルを避けることができるでしょうか。したがって、重要なのは、常に f または argument.callee を介して関数を参照することです。名前付き関数式を使用する場合は、デバッグ時にのみその名前を使用する必要があります。最後に、名前付き関数式の宣言中に誤って作成された関数をクリーンアップすることを忘れないでください。

2. JScript のメモリ管理

これらの非標準コード解析のバグを理解した後、それを使用すると、実際にはメモリに問題があることがわかります。例を見てみましょう。

var f = (function(){
 if (true) {
 return function g(){};
 }
 return function g(){};
})();
ログイン後にコピー

我们知道,这个匿名函数调用返回的函数(带有标识符g的函数),然后赋值给了外部的f。我们也知道,命名函数表达式会导致产生多余的函数对象,而该对象与返回的函数对象不是一回事。所以这个多余的g函数就死在了返回函数的闭包中了,因此内存问题就出现了。这是因为if语句内部的函数与g是在同一个作用域中被声明的。这种情况下 ,除非我们显式断开对g函数的引用,否则它一直占着内存不放。

var f = (function(){
 var f, g;
 if (true) {
 f = function g(){};
 }
 else {
 f = function g(){};
 }
 // 设置g为null以后它就不会再占内存了
 g = null;
 return f;
})();
ログイン後にコピー

通过设置g为null,垃圾回收器就把g引用的那个隐式函数给回收掉了,为了验证我们的代码,我们来做一些测试,以确保我们的内存被回收了。

测试

测试很简单,就是命名函数表达式创建10000个函数,然后把它们保存在一个数组中。等一会儿以后再看这些函数到底占用了多少内存。然后,再断开这些引用并重复这一过程。下面是测试代码:

function createFn(){
 return (function(){
 var f;
 if (true) {
  f = function F(){
  return 'standard';
  };
 }
 else if (false) {
  f = function F(){
  return 'alternative';
  };
 }
 else {
  f = function F(){
  return 'fallback';
  };
 }
 // var F = null;
 return f;
 })();
}

var arr = [ ];
for (var i=0; i < 10000; i++) {
 arr[i] = createFn();
}

ログイン後にコピー

通过运行在Windows XP SP2中的任务管理器可以看到如下结果:

IE7:

 without `null`: 7.6K -> 20.3K
 with `null`:  7.6K -> 18K

IE8:

 without `null`: 14K -> 29.7K
 with `null`:  14K -> 27K

ログイン後にコピー

如我们所料,显示断开引用可以释放内存,但是释放的内存不是很多,10000个函数对象才释放大约3M的内存,这对一些小型脚本不算什么,但对于大型程序,或者长时间运行在低内存的设备里的时候,这是非常有必要的。

以上就是关于JScript的Bug与内存管理的全部介绍,希望对大家的学习有所帮助。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

C++ オブジェクトのレイアウトはメモリに合わせて調整され、メモリの使用効率が最適化されます。 C++ オブジェクトのレイアウトはメモリに合わせて調整され、メモリの使用効率が最適化されます。 Jun 05, 2024 pm 01:02 PM

C++ オブジェクト レイアウトとメモリ アライメントにより、メモリ使用効率が最適化されます。 オブジェクト レイアウト: データ メンバーは宣言の順序で格納され、スペース使用率が最適化されます。メモリのアライメント: アクセス速度を向上させるために、データがメモリ内でアライメントされます。 alignas キーワードは、キャッシュ ラインのアクセス効率を向上させるために、64 バイトにアライメントされた CacheLine 構造などのカスタム アライメントを指定します。

Apple iOS18 のバグの概要 Apple iOS18 のバグの概要 Jun 14, 2024 pm 01:48 PM

Apple の WWDC カンファレンス 2024 が成功裡に終了する中、macos15 が発表されただけでなく、Apple の新しい iOS18 システムのアップデートが最も注目を集めました。Apple の iOS18 の最初のバージョンとして、多くの新機能がありますが、人々は必然的にそれがどうか疑問に思います。 Apple iOS18 にアップグレードする必要がありますが、Apple iOS18 の最新リリースにはどのようなバグがありますか?実際の使用評価の後、以下に Apple iOS 18 のバグの概要を示しますので、見てみましょう。現在、多くのiPhoneユーザーがiOS18へのアップグレードを急いでいますが、さまざまなシステムバグが人々を不快にさせています。一部のブロガーは、「バグが非常に多い」ため、iOS18にアップグレードする場合は注意する必要があると述べています。ブロガーは、あなたのiPhoneが

C++ 関数のメモリ割り当てと破棄のための拡張機能と高度なテクニック C++ 関数のメモリ割り当てと破棄のための拡張機能と高度なテクニック Apr 22, 2024 pm 05:21 PM

C++ 関数のメモリ管理は、次のような拡張機能と高度なテクノロジを提供します。 カスタム アロケータ: ユーザーが独自のメモリ割り当て戦略を定義できるようにします。 Placementnew と Placementdelete: オブジェクトを特定のメモリ位置に割り当てる必要がある場合に使用されます。高度なテクノロジ: メモリ プール、スマート ポインタ、および RAII により、メモリ リークを削減し、パフォーマンスを向上させ、コードを簡素化します。

C++ メモリ管理: カスタム メモリ アロケータ C++ メモリ管理: カスタム メモリ アロケータ May 03, 2024 pm 02:39 PM

C++ のカスタム メモリ アロケータを使用すると、開発者は必要に応じてメモリ割り当て動作を調整できます。カスタム アロケータを作成するには、std::allocator を継承し、allocate() 関数と deallocate() 関数を書き直す必要があります。実際の例としては、パフォーマンスの向上、メモリ使用量の最適化、特定の動作の実装などが挙げられます。使用する場合は、メモリの解放を避けること、メモリのアライメントを管理すること、ベンチマーク テストを実行することなどに注意する必要があります。

大規模なコード ベースにおける C++ 関数のメモリ割り当てと破棄のベスト プラクティス 大規模なコード ベースにおける C++ 関数のメモリ割り当てと破棄のベスト プラクティス Apr 22, 2024 am 11:09 AM

C++ 関数のメモリ割り当てと破棄のベスト プラクティスには、静的メモリ割り当てにローカル変数を使用することが含まれます。動的メモリ割り当てにはスマート ポインタを使用します。メモリはコンストラクターで割り当てられ、デストラクターで破棄されます。複雑なメモリ シナリオにはカスタム メモリ マネージャーを使用します。例外処理を使用してリソースをクリーンアップし、例外が発生したときに割り当てられたメモリが確実に解放されるようにします。

C++ メモリ管理における参照カウント メカニズム C++ メモリ管理における参照カウント メカニズム Jun 01, 2024 pm 08:07 PM

参照カウント メカニズムは、C++ メモリ管理でオブジェクト参照を追跡し、未使用のメモリを自動的に解放するために使用されます。このテクノロジはオブジェクトごとに参照カウンタを維持し、参照が追加または削除されるとカウンタが増減します。カウンタが 0 になると、オブジェクトは手動管理なしで解放されます。ただし、循環参照はメモリ リークを引き起こす可能性があり、参照カウンタを維持するとオーバーヘッドが増加します。

マルチスレッド環境における C++ メモリ管理の課題と対策? マルチスレッド環境における C++ メモリ管理の課題と対策? Jun 05, 2024 pm 01:08 PM

マルチスレッド環境では、C++ メモリ管理はデータ競合、デッドロック、メモリ リークなどの課題に直面します。対策には次のものが含まれます: 1. ミューテックスやアトミック変数などの同期メカニズムの使用、 2. ロックフリーのデータ構造の使用、 4. (オプション) ガベージ コレクションの実装。

PHP 関数でのメモリ使用量を管理するにはどうすればよいですか? PHP 関数でのメモリ使用量を管理するにはどうすればよいですか? Apr 26, 2024 pm 12:12 PM

PHP 関数でのメモリ使用量を管理するには、不要な変数の宣言を回避し、未使用の変数を解放し、ループと条件を最適化します (無限ループの回避やインデックス付き配列の使用など)。

See all articles