JavaScript はメモリ最適化_JavaScript スキルについても語っています
C/C と比較して、私たちが使用する JavaScript のメモリ処理により、開発中にビジネス ロジックの記述により注意を払うことができます。しかし、ビジネスの継続的な複雑化と、シングルページ アプリケーション、モバイル HTML5 アプリケーション、Node.js プログラムなどの開発により、JavaScript のメモリ問題によって引き起こされる遅延やメモリ オーバーフローなどの現象は、もはや珍しいものではなくなりました。
この記事では、JavaScript の言語レベルからメモリ使用量と最適化について説明します。誰もがよく知っている、少しは聞いたことのあるところから、あまり気づかないところまで、一つ一つ分析していきます。
1. 言語レベルのメモリ管理
1.1 範囲
スコープは JavaScript プログラミングにおいて非常に重要な操作メカニズムであり、同期 JavaScript プログラミングではあまり注目されませんが、非同期プログラミングでは、優れたスコープ制御スキルが JavaScript 開発の鍵となります。さらに、スコープは JavaScript のメモリ管理において重要な役割を果たします。
JavaScript では、ステートメントとグローバル スコープを使用した関数呼び出しによってスコープを形成できます。
次のコードを例に挙げます。
var foo = function() {
var local = {};
};
foo();
console.log(local); //=>
var bar = function() {
local = {};
};
bar();
console.log(local) {}
foo() 関数では、var ステートメントを使用してローカル変数を宣言および定義します。スコープが関数本体内に形成されるため、この変数はスコープ内で定義されます。また、foo()関数本体ではスコープ拡張処理を行っていないため、関数実行後にローカル変数も破棄されます。外部スコープでは変数にアクセスできません。
bar() 関数では、ローカル変数は var ステートメントを使用して宣言されず、代わりにグローバル変数として直接定義されます。したがって、外側のスコープはこの変数にアクセスできます。
/ / ここでの定義は、
global.local = {};
1.2 スコープチェーン
と同等です。JavaScript プログラミングでは、複数レベルの関数のネストを含むシナリオに遭遇した場合、これは典型的なスコープ チェーンの表現です。 次のコードに示すように:
var val = 'hello';
function bar() {
function baz() {
global.val = 'world;'
}
baz ();
console.log(val); //=> hello
}
bar();
}
foo();
JavaScript では、変数識別子の検索は現在のスコープから開始され、グローバル スコープまで外側に向かって検索されます。したがって、JavaScript コード内の変数へのアクセスは外部からのみ行うことができ、その逆はできません。
baz() 関数の実行により、グローバル スコープでグローバル変数 val が定義されます。 bar() 関数では、識別子 val にアクセスするとき、検索原則は内側から外側へです。bar 関数のスコープ内で見つからない場合は、上位レベル、つまり foo のスコープに進みます。 () 関数の範囲内で検索します。
1.3 終了
JavaScript での識別子の検索はインサイドアウトの原則に従っていることはわかっています。ただし、ビジネス ロジックが複雑なため、単一の配信シーケンスでは増大する新たなニーズを満たすには程遠いです。まず次のコードを見てみましょう:
function foo() {
var local = 'Hello';
return function() {
return local;
};
}
var bar = foo();
console.log(bar()); //=> こんにちは
ここで示した、外側のスコープが内側のスコープにアクセスできるようにするテクノロジーは、クロージャ (Closure) です。高階関数の適用のおかげで、foo() 関数のスコープが「拡張」されました。
foo() 関数は、foo() 関数のスコープ内に存在する匿名関数を返すため、foo() 関数のスコープ内でローカル変数にアクセスし、その参照を保存できます。この関数はローカル変数を直接返すため、外側のスコープで bar() 関数を直接実行してローカル変数を取得できます。
クロージャは JavaScript の高度な機能であり、これを使用してさまざまなニーズを満たす、より複雑な効果を実現できます。ただし、内部変数参照を持つ関数は関数から取り出されるため、関数実行後、内部変数への参照がすべて解放されるまでスコープ内の変数が必ずしも破棄されるわけではないことに注意してください。したがって、クロージャを適用すると、メモリを解放できなくなりやすくなります。
2. JavaScript のメモリ再利用メカニズム
ここでは、Chrome と Node.js で使用されている Google が発表した V8 エンジンを例として、JavaScript のメモリ リサイクル メカニズムを簡単に紹介します。さらに詳しい内容については、私の友人である Pu Ling の著書「Speaking in」を購入してください。シンプルで奥深い言語「Node.js」を学ぶには、「メモリ制御」の章にかなり詳しく紹介されています。
V8 では、すべての JavaScript オブジェクトに「ヒープ」を通じてメモリが割り当てられます。
コード内で変数を宣言して値を割り当てると、V8 はヒープ メモリの一部をその変数に割り当てます。割り当てられたメモリがこの変数を格納するのに十分でない場合、V8 はヒープ サイズが V8 のメモリ制限に達するまでメモリを適用し続けます。デフォルトでは、V8 のヒープ メモリ サイズの上限は、64 ビット システムでは 1464 MB、32 ビット システムでは 732 MB で、それぞれ約 1.4 GB と 0.7 GB です。
さらに、V8 はヒープ メモリ内の JavaScript オブジェクトを世代 (新世代と旧世代) ごとに管理します。新しい世代は、一時変数、文字列など、ライフサイクルの短い JavaScript オブジェクトを指しますが、古い世代は、メイン コントローラー、サーバー オブジェクトなど、複数のガベージ コレクションを経てライフ サイクルが長いオブジェクトを指します。 、など。
ガベージ コレクション アルゴリズムは常にプログラミング言語開発の重要な部分であり、V8 で使用されるガベージ コレクション アルゴリズムには主に次のものが含まれます。
1. スカバンジアルゴリズム: コピーによるメモリ空間管理。主に新世代のメモリ空間に使用されます。
2. マークスイープアルゴリズムとマークコンパクトアルゴリズム: マーキングによるヒープメモリの整理と整理。主に古い世代のオブジェクトの検査とリサイクルに使用されます。
追記: V8 ガベージ コレクションの実装の詳細については、関連する書籍、ドキュメント、ソース コードを読むことで学ぶことができます。
JavaScript エンジンがどのような状況でどのオブジェクトをリサイクルするかを見てみましょう。
2.1 範囲と参照
初心者は、関数の実行が完了すると、関数内で宣言されたオブジェクトが破棄されると誤解することがよくあります。しかし実際には、この理解は厳密かつ包括的ではなく、簡単に混乱を招く可能性があります。
参照は JavaScript プログラミングにおいて非常に重要なメカニズムですが、奇妙なことに、ほとんどの開発者はそれに注意を払っておらず、理解さえしていません。参照は、「コードによるオブジェクトへのアクセス」という抽象的な関係を指します。これは C/C ポインターに似ていますが、同じものではありません。参照は、JavaScript エンジンによるガベージ コレクションの最も重要なメカニズムでもあります。
例として次のコードを取り上げます。
// ..
var val = 'hello world';
function foo() {
return function() {
return val;
};
}
global.bar = foo();
// ......
このコードを読んで、コードのこの部分が実行された後もどのオブジェクトがまだ生きているかわかりますか?
関連する原則によれば、このコード内のリサイクルされていないオブジェクトには val と bar() が含まれます。これらがリサイクルできない理由は何ですか?
JavaScript エンジンはガベージ コレクションをどのように実行しますか?前述のガベージ コレクション アルゴリズムは、リサイクル中にのみ使用されます。では、どのオブジェクトがリサイクル可能で、どのオブジェクトが存続する必要があるかをどのように判断するのでしょうか?答えは、JavaScript オブジェクトへの参照です。
JavaScript コードでは、何も操作せずに変数名を別行で記述するだけでも、JavaScript エンジンはこれがオブジェクトへのアクセス動作であると認識し、オブジェクトへの参照が存在します。ガベージ コレクションの動作がプログラム ロジックの動作に影響を与えないようにするために、JavaScript エンジンは使用されているオブジェクトをリサイクルしてはなりません。リサイクルしないと混乱が生じます。したがって、オブジェクトが使用中かどうかを判断する基準は、そのオブジェクトへの参照がまだ存在するかどうかです。しかし実際には、これは妥協策です。JavaScript 参照は転送できるため、一部の参照はグローバル スコープに持ち込まれる可能性がありますが、実際には、アクセスされたらリサイクルする必要があるため、ビジネス ロジックでそれらを変更する必要はありません。しかし、JavaScript エンジンは依然としてプログラムがそれを必要としていると固く信じます。
変数と参照を正しく使用する方法は、言語レベルから JavaScript を最適化するための鍵です。
3. JavaScript を最適化します
ようやく本題に入ります。ここまで読んでいただき、ありがとうございました。これで、JavaScript のメモリ管理メカニズムについては十分に理解できたと思います。その後、次のテクニックを使用すると、さらに強力になります。 。
3.1 機能を上手に活用する
優れた JavaScript プロジェクトを読む習慣がある方は、多くの専門家がフロントエンド JavaScript コードを開発する際に、コードの最外層をラップするために匿名関数をよく使用していることがわかるでしょう。
(function() {
/ / メイン ビジネス コード
})();
一部はさらに高度です:
;(function(win, doc, $, unknown) {
// メイン ビジネス コード
})(window, document, jQuery);
RequireJS、SeaJS、OzJS などのフロントエンドのモジュラー読み込みソリューションでも、同様の形式を採用しています:
// RequireJS
define(['jquery'], function($) {
// メイン ビジネス コード
});
// SeaJS
define('module', ['dep', 'underscore'], function($, _) {
// メインのビジネスコード
});
多くの Node.js オープンソース プロジェクトのコードがこの方法で処理されていないと言ったら、それは間違いです。実際にコードを実行する前に、Node.js は各 .js ファイルを次の形式にパッケージ化します:
(function(exports, require, module, __dirname, __filename) {
// メイン ビジネス コード
});
これを行うことの利点は何ですか?記事の冒頭で述べたように、JavaScript のスコープにはステートメントとグローバル スコープを伴う関数呼び出しが含まれていることは誰もが知っています。また、グローバル スコープで定義されたオブジェクトは、大きなオブジェクトの場合、プロセスが終了するまで存続する可能性が高く、問題が発生することもわかっています。たとえば、JavaScript でテンプレートのレンダリングを行うことを好む人もいます。
$db = mysqli_connect(server, user, password, 'myapp');
$topics = mysqli_query($db, "SELECT * FROM topic;");
?>
- < ;/ul>
この種のコードは新しい作品で頻繁に見られますが、ここに何か問題がありますか? データ プールから取得したデータの量が通常よりも大きい場合、フロントエンドがモールド プレートの汚染を完了した後、データ量がこの量は、完全なアクション ドメイン内で定義されているため、JavaScript によってバックグラウンドでブロックされることはありません。
が、コードの外装の 1 層の関数にいくつかの非常に単純な変更を加えた場合、その効果は大きく異なります。UI の染まりが完了すると、データの参照も同時にキャンセルされ、最終的にはレイヤー関数の実行が完了すると、JavaScript 引数がその中のオブジェクトの検査を開始し、データも同時に取得されます。 3.2 绝对不要定义全局变量
我们刚才也谈到了,当一变量被定义在全局作用域中,默认情况下JavaScript 引擎就不会将其回收销毁このように、この量は、トップが遮断されるまで、老朽化したスタック内に存在し続けます。
私たちは、原則に忠実に従う: 全局所量を不必要に使用することは禁止されている。しかし、全局所量は、開発当初は非常に節約されているが、それによって生じる問題は、その利点に比べてより重い。
量が回収されにくくする;
2. 作業領域内で混乱しやすくなる。 『全局所量』はpackage関数により処理されます。
3.3 手動での量参照のキャンセル
复制代
3.4 善用回覧
复制代码
function getData(callback) {
var data = 'ビッグデータ';
callback(null, data);
}
getData(function (エラー、データ) {
console.log(data);
コールバック関数は Continuation Passing Style (CPS) テクノロジであり、このスタイルのプログラミングでは、関数のビジネスの焦点が戻り値からコールバック関数に移されます。そして、クロージャに比べて多くの利点があります:
1. 渡されたパラメータが基本型 (文字列、数値など) の場合、ビジネス コードを使用した後、値がコピーされます。 >2 .コールバックを通じて、同期リクエストを完了するだけでなく、現在非常に人気のある記述スタイルである非同期プログラミングでも使用できます。
3. コールバック関数自体は、通常、リクエスト後に一時的な匿名関数です。関数が実行されると、コールバック関数自体の参照が解放され、それ自体がリサイクルされます。
3.5 適切な閉鎖管理
ビジネス要件 (ループ イベント バインディング、プライベート プロパティ、パラメーターを含むコールバックなど) でクロージャーを使用する必要がある場合は、詳細に注意してください。ループ バインディング イベントは、JavaScript クロージャを始めるための必須コースであると言えます。6 つのボタンがあり、ユーザーが 6 種類のイベントに対応してボタンをクリックすると、対応するイベントが出力されます。指定された場所で。
var Output = document.querySelector('#output');
var events = [1, 2, 3, 4, 5, 6];
// ケース 1
for (var i = 0; i
Output.innerText = 'クリックしました ' events [i];
};
}
// ケース 2
for (var i = 0; i
};
btns [i] .onclick = (function(index) {
return function(evt) {
Output.innerText = 'クリックされた' events[index];
};
})(i);
}
// ケース 3
for (var i = 0; i
return function(evt) {
output.innerText = 'クリック' イベント;
};
})(events[i]);
}
ここでの最初の解決策は明らかに典型的なループ バインディング イベント エラーです。詳細については、私がネットユーザーに提供した回答を参照してください。2 番目と 3 番目の解決策の違いは次のとおりです。受信クロージャパラメータ内。
2 番目のソリューションで渡されるパラメーターは現在のループの添字ですが、後者は対応するイベント オブジェクトを直接渡します。実際、後者の方が大規模なデータ アプリケーションに適しています。JavaScript 関数型プログラミングでは、関数の呼び出し時に渡されるパラメーターは基本型オブジェクトであるため、関数本体で取得される仮パラメーターはコピーされた値になります。この値は、関数本体のスコープ内のローカル変数として定義されます。イベント バインディングの完了後、イベント変数を手動で逆参照して、外側のスコープでのメモリ使用量を削減できます。また、要素が削除されると、対応するイベント リスニング関数、イベント オブジェクト、およびクロージャー関数も破棄され、リサイクルされます。
3.6 メモリはキャッシュではありません
キャッシュはビジネス開発において重要な役割を果たし、時間とスペースのリソースの負担を軽減できます。ただし、メモリを安易にキャッシュとして使用しないように注意してください。メモリはプログラム開発にとって貴重なリソースです。それが非常に重要なリソースでない場合は、メモリに直接配置しないようにするか、期限切れのキャッシュを自動的に破棄する有効期限メカニズムを開発してください。
4. JavaScript のメモリ使用量を確認します
日々の開発では、いくつかのツールを使用して JavaScript のメモリ使用量を分析し、トラブルシューティングすることもできます。
4.1 ブリンク / Webkit ブラウザ
Blink/Webkit ブラウザ (Chrome、Safari、Opera など) では、開発者ツールのプロファイル ツールを使用してプログラムのメモリをチェックできます。
4.2 Node.js でのメモリチェック
Node.js では、メモリ チェックに node-heapdump モジュールと node-memwatch モジュールを使用できます。
var heapdump = require('heapdump') ;
var fs = require('fs');
var path = require('path');
fs.writeFileSync(path.join(__dirname, 'app.pid'), process.pid );
// ...
In this way, there will be a snapshot file named in the format of heapdump-
5. Summary
The end of the article soon came. This sharing mainly shows you the following points:
1. JavaScript is closely related to memory usage at the language level;
2. Memory management and recycling mechanism in JavaScript;
3. How to use memory more efficiently so that the produced JavaScript Can have more vitality for expansion;
4. How to perform memory check when encountering memory problems.
I hope that by studying this article, you can produce better JavaScript code, which will reassure your mother and your boss.

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

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

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

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

ホットトピック









C++ は効率的で強力なプログラミング言語ですが、大規模なデータを処理したり、複雑なプログラムを実行したりする場合、開発者にとってメモリの最適化は無視できない問題になります。メモリ使用量を適切に管理して削減すると、プログラムのパフォーマンスと信頼性が向上します。この記事では、開発者がより効率的なアプリケーションを構築できるように、C++ でメモリ フットプリントを削減するための重要なヒントをいくつか紹介します。適切なデータ型を使用する C++ プログラミングでは、適切なデータ型を選択することがメモリ使用量を削減するための重要な手順です。たとえば、狭い範囲の整数のみを表す必要がある場合は、次のように使用できます。

WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法 はじめに: 技術の継続的な発展により、音声認識技術は人工知能の分野の重要な部分になりました。 WebSocket と JavaScript をベースとしたオンライン音声認識システムは、低遅延、リアルタイム、クロスプラットフォームという特徴があり、広く使用されるソリューションとなっています。この記事では、WebSocket と JavaScript を使用してオンライン音声認識システムを実装する方法を紹介します。

WebSocketとJavaScript:リアルタイム監視システムを実現するためのキーテクノロジー はじめに: インターネット技術の急速な発展に伴い、リアルタイム監視システムは様々な分野で広く利用されています。リアルタイム監視を実現するための重要なテクノロジーの 1 つは、WebSocket と JavaScript の組み合わせです。この記事では、リアルタイム監視システムにおける WebSocket と JavaScript のアプリケーションを紹介し、コード例を示し、その実装原理を詳しく説明します。 1.WebSocketテクノロジー

JavaScript と WebSocket を使用してリアルタイム オンライン注文システムを実装する方法の紹介: インターネットの普及とテクノロジーの進歩に伴い、ますます多くのレストランがオンライン注文サービスを提供し始めています。リアルタイムのオンライン注文システムを実装するには、JavaScript と WebSocket テクノロジを使用できます。 WebSocket は、TCP プロトコルをベースとした全二重通信プロトコルで、クライアントとサーバー間のリアルタイム双方向通信を実現します。リアルタイムオンラインオーダーシステムにおいて、ユーザーが料理を選択して注文するとき

WebSocket と JavaScript を使用してオンライン予約システムを実装する方法 今日のデジタル時代では、ますます多くの企業やサービスがオンライン予約機能を提供する必要があります。効率的かつリアルタイムのオンライン予約システムを実装することが重要です。この記事では、WebSocket と JavaScript を使用してオンライン予約システムを実装する方法と、具体的なコード例を紹介します。 1. WebSocket とは何ですか? WebSocket は、単一の TCP 接続における全二重方式です。

JavaScript と WebSocket: 効率的なリアルタイム天気予報システムの構築 はじめに: 今日、天気予報の精度は日常生活と意思決定にとって非常に重要です。テクノロジーの発展に伴い、リアルタイムで気象データを取得することで、より正確で信頼性の高い天気予報を提供できるようになりました。この記事では、JavaScript と WebSocket テクノロジを使用して効率的なリアルタイム天気予報システムを構築する方法を学びます。この記事では、具体的なコード例を通じて実装プロセスを説明します。私たちは

JavaScript チュートリアル: HTTP ステータス コードを取得する方法、特定のコード例が必要です 序文: Web 開発では、サーバーとのデータ対話が頻繁に発生します。サーバーと通信するとき、多くの場合、返された HTTP ステータス コードを取得して操作が成功したかどうかを判断し、さまざまなステータス コードに基づいて対応する処理を実行する必要があります。この記事では、JavaScript を使用して HTTP ステータス コードを取得する方法を説明し、いくつかの実用的なコード例を示します。 XMLHttpRequestの使用

使用法: JavaScript では、insertBefore() メソッドを使用して、DOM ツリーに新しいノードを挿入します。このメソッドには、挿入される新しいノードと参照ノード (つまり、新しいノードが挿入されるノード) の 2 つのパラメータが必要です。
