検索
ホームページウェブフロントエンドjsチュートリアル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() 関数と bar() 関数を定義します。これらの目的は、local という名前の変数を定義することです。しかし、最終的な結果はまったく異なりました。

foo() 関数では、var ステートメントを使用してローカル変数を宣言および定義します。スコープが関数本体内に形成されるため、この変数はスコープ内で定義されます。また、foo()関数本体ではスコープ拡張処理を行っていないため、関数実行後にローカル変数も破棄されます。外部スコープでは変数にアクセスできません。

bar() 関数では、ローカル変数は var ステートメントを使用して宣言されず、代わりにグローバル変数として直接定義されます。したがって、外側のスコープはこの変数にアクセスできます。


コードをコピー コードは次のとおりです:
local = {};
/ / ここでの定義は、
global.local = {};



1.2 スコープチェーン

と同等です。JavaScript プログラミングでは、複数レベルの関数のネストを含むシナリオに遭遇した場合、これは典型的なスコープ チェーンの表現です。
次のコードに示すように:


コードをコピーします コードは次のとおりです:
function foo( ) {
var val = 'hello';

function bar() {
function baz() {
global.val = 'world;'
}
baz ();
console.log(val); //=> hello
}
bar();
}
foo();

スコープに関する前述の説明に基づいて、ここのコードによって表示される結果は world であると思われるかもしれませんが、実際の結果は hello です。多くの初心者はここで混乱し始めるので、このコードがどのように機能するかを見てみましょう。

JavaScript では、変数識別子の検索は現在のスコープから開始され、グローバル スコープまで外側に向かって検索されます。したがって、JavaScript コード内の変数へのアクセスは外部からのみ行うことができ、その逆はできません。

JavaScript はメモリ最適化_JavaScript スキルについても語っています
baz() 関数の実行により、グローバル スコープでグローバル変数 val が定義されます。 bar() 関数では、識別子 val にアクセスするとき、検索原則は内側から外側へです。bar 関数のスコープ内で見つからない場合は、上位レベル、つまり foo のスコープに進みます。 () 関数の範囲内で検索します。

しかし、誰もが混乱する鍵はここにあります。この識別子アクセスは foo() 関数のスコープ内で一致する変数を見つけますが、外側への検索は続行しないため、baz() 関数内で定義されたグローバル変数val は、この変数アクセスには影響しません。

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 オブジェクトに「ヒープ」を通じてメモリが割り当てられます。

JavaScript はメモリ最適化_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;");
?>




你は猴子请来の逗比么?






この種のコードは新しい作品で頻繁に見られますが、ここに何か問題がありますか? データ プールから取得したデータの量が通常よりも大きい場合、フロントエンドがモールド プレートの汚染を完了した後、データ量がこの量は、完全なアクション ドメイン内で定義されているため、JavaScript によってバックグラウンドでブロックされることはありません。

が、コードの外装の 1 層の関数にいくつかの非常に単純な変更を加えた場合、その効果は大きく異なります。UI の染まりが完了すると、データの参照も同時にキャンセルされ、最終的にはレイヤー関数の実行が完了すると、JavaScript 引数がその中のオブジェクトの検査を開始し、データも同時に取得されます。

3.2 绝对不要定义全局变量


我们刚才也谈到了,当一变量被定义在全局作用域中,默认情况下JavaScript 引擎就不会将其回收销毁このように、この量は、トップが遮断されるまで、老朽化し​​たスタック内に存在し続けます。
私たちは、原則に忠実に従う: 全局所量を不必要に使用することは禁止されている。しかし、全局所量は、開発当初は非常に節約されているが、それによって生じる問題は、その利点に比べてより重い。
量が回収されにくくする;

1. 複数人で作業すると混み合いが発生しやすくなる;

2. 作業領域内で混乱しやすくなる。 『全局所量』はpackage関数により処理されます。


3.3 手動での量参照のキャンセル

トラフィックコード内で、すでに必要でない量があれば、手動で量の参照をキャンセルして、それを取り戻すことができます。



复制代

代码如下:var data = { /* ビッグデータ */ } ;// 何とか何とか何とかdata = null;


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 btns = document.querySelectorAll ('.btn'); // 6 要素
var Output = document.querySelector('#output');
var events = [1, 2, 3, 4, 5, 6];

// ケース 1
for (var i = 0; i btns[i].onclick = function(evt) {
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 btns[i].onclick = (function(event) {
return function(evt) {
output.innerText = 'クリック' イベント;
};
})(events[i]);
}

ここでの最初の解決策は明らかに典型的なループ バインディング イベント エラーです。詳細については、私がネットユーザーに提供した回答を参照してください。2 番目と 3 番目の解決策の違いは次のとおりです。受信クロージャパラメータ内。

2 番目のソリューションで渡されるパラメーターは現在のループの添字ですが、後者は対応するイベント オブジェクトを直接渡します。実際、後者の方が大規模なデータ アプリケーションに適しています。JavaScript 関数型プログラミングでは、関数の呼び出し時に渡されるパラメーターは基本型オブジェクトであるため、関数本体で取得される仮パラメーターはコピーされた値になります。この値は、関数本体のスコープ内のローカル変数として定義されます。イベント バインディングの完了後、イベント変数を手動で逆参照して、外側のスコープでのメモリ使用量を削減できます。また、要素が削除されると、対応するイベント リスニング関数、イベント オブジェクト、およびクロージャー関数も破棄され、リサイクルされます。

3.6 メモリはキャッシュではありません

キャッシュはビジネス開発において重要な役割を果たし、時間とスペースのリソースの負担を軽減できます。ただし、メモリを安易にキャッシュとして使用しないように注意してください。メモリはプログラム開発にとって貴重なリソースです。それが非常に重要なリソースでない場合は、メモリに直接配置しないようにするか、期限切れのキャッシュを自動的に破棄する有効期限メカニズムを開発してください。

4. JavaScript のメモリ使用量を確認します

日々の開発では、いくつかのツールを使用して JavaScript のメモリ使用量を分析し、トラブルシューティングすることもできます。

4.1 ブリンク / Webkit ブラウザ

Blink/Webkit ブラウザ (Chrome、Safari、Opera など) では、開発者ツールのプロファイル ツールを使用してプログラムのメモリをチェックできます。

JavaScript はメモリ最適化_JavaScript スキルについても語っています
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 );
// ...

Copy code The code is as follows:
After introducing node-heapdump in the business code, we need to send data to Node.js at a certain runtime The process sends the SIGUSR2 signal to let node-heapdump take a snapshot of the heap memory.

Copy code The code is as follows:
$ kill -USR2 (cat app .pid)

In this way, there will be a snapshot file named in the format of heapdump-..heapsnapshot in the file directory. We can use the Profiles tool in the browser's Developer Tools to open it and check it. .

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.

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

See all articles

ホット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ヘンタイを無料で生成します。

ホットツール

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

SublimeText3 Mac版

SublimeText3 Mac版

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

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境