関連する推奨事項: 「JavaScript ビデオ チュートリアル 」
ほとんどの場合、私たちはメモリ管理に関する知識を理解せずに開発するだけです。 JS エンジンがこれを処理します。ただし、メモリ リークなどの問題が発生する場合があり、メモリ割り当ての仕組みを知ることによってのみ、これらの問題を解決できます。
この記事では、主に メモリ割り当て と ガベージ コレクション の動作原理と、いくつかの一般的な メモリ リーク 問題を回避する方法を紹介します。
キャッシュ (メモリ) ライフ サイクル
JS では、変数、関数、またはオブジェクトを作成すると、JS エンジンがそれにメモリを割り当て、不要になったら解放します。
メモリの割り当てはメモリ内のスペースを予約するプロセスであり、メモリの解放はスペースを解放して他の目的に備えます。
変数を割り当てたり、関数を作成したりするたびに、その変数の保存は同じ段階を経ます:
メモリの割り当て
- JS がこれを処理し、オブジェクトの作成に必要なメモリを割り当てます。
メモリの使用
- メモリの使用は、コード内で明示的に実行します: メモリの読み取りと書き込みは、実際には変数の読み取りと書き込みです。書く。
メモリの解放
- このステップも JS エンジンによって処理され、割り当てられたメモリが解放されると、新しい目的に使用できるようになります。 。
メモリ管理の文脈における「オブジェクト」には、JS オブジェクトだけでなく、関数や関数スコープも含まれます。
メモリ ヒープとスタック
これで、JS で定義したすべてのものに対して、エンジンがメモリを割り当て、メモリが不要になったときにメモリを解放することがわかりました。
次に頭に浮かぶ疑問は、これらのものはどこに保管されるのかということです。
JS エンジンは、メモリ ヒープと スタックの 2 つの場所にデータを保存できます。ヒープとスタックは、エンジンによってさまざまな目的で使用される 2 つのデータ構造です。
スタック: 静的メモリ割り当て
スタックは、JS が静的データを保存するために使用するデータ構造です。静的データは、エンジンがコンパイル時にサイズを認識しているデータです。 JS には、オブジェクトと関数を指すプリミティブ値が含まれます (strings
、number
、boolean
、undependent
、および null
) と参照型。
エンジンはサイズが変わらないことを認識しているため、各値に固定量のメモリを割り当てます。
実行直前にメモリを割り当てるプロセスは、静的メモリ割り当てと呼ばれます。これらの値とスタック全体の制限はブラウザーに依存します。
ヒープ: 動的メモリ割り当て
ヒープはデータを保存するための別のスペースであり、JS はここに objects と functions を保存します。
スタックとは異なり、JS エンジンはこれらのオブジェクトに固定量のメモリを割り当てませんが、必要に応じてスペースを割り当てます。このメモリ割り当て方法は、動的メモリ割り当てとも呼ばれます。
これら 2 つのストアの特徴を以下で比較します。
スタック | ヒープ |
---|---|
ストレージの基本型と参照 サイズはコンパイル時に判明します 固定量のメモリを割り当てます |
オブジェクトと関数 サイズはコンパイル時に判明しますランタイム 制限なし |
例
イメージを強化するためにいくつかの例を見てみましょう。
const person = { name: 'John', age: 24, };
JS は、ヒープ内のこのオブジェクトにメモリを割り当てます。実際の値は元の値のままであるため、スタックに保存されます。
const hobbies = ['hiking', 'reading'];
配列もオブジェクトなので、ヒープに格納されます。
let name = 'John'; // 为字符串分配内存 const age = 24; // 为字分配内存 name = 'John Doe'; // 为新字符串分配内存 const firstName = name.slice(0,4); // 为新字符串分配内存
初期値は不変であるため、JS は元の値を変更せず、新しい値を作成します。
JavaScript での参照
すべての変数は最初に stack を指します。非プリミティブ値の場合、 スタック
には ヒープ
内のオブジェクトへの参照が含まれます。
ヒープ メモリは特定の方法で並べ替えられていないため、スタック上にヒープ メモリへの参照を保持する必要があります。 references
をアドレス、ヒープ内のオブジェクトをそれらのアドレスが属するハウスと考えることができます。
JS は objects と functions をヒープに保存することに注意してください。プリミティブ型と参照はスタックに保存されます。
この写真では、さまざまな値がどのように保存されているかを観察できます。 person
と newperson
がどちらも同じオブジェクトを指していることに注目してください。
例
const person = { name: 'John', age: 24, };
これにより、ヒープ内に新しいオブジェクトが作成され、スタック上にそのオブジェクトへの参照が作成されます。
ガベージ コレクション
JS がさまざまなオブジェクトにメモリを割り当てる方法がわかりましたが、メモリのライフ サイクルには最後のステップが 1 つあります: メモリを解放する。
メモリ割り当てと同様に、JavaScript エンジンがこのステップも処理します。より具体的には、ガベージ コレクターがこのジョブを担当します。
JS エンジンは、変数または関数が不要になったことを認識すると、占有していたメモリを解放します。
これに関する主な問題は、一部のメモリがまだ必要かどうかが判断できないことです。つまり、不要になった瞬間にすべてのメモリを即座に収集できるアルゴリズムを使用することは不可能です。不要になりました。
一部のアルゴリズムはこの問題をうまく解決できます。このセクションでは、最も一般的な方法である 参照カウント
アルゴリズムと マーク クリアリング
アルゴリズムについて説明します。
参照カウント
変数が宣言され、その変数に参照型の値が割り当てられると、この値への参照の数は 1
になります。同じ値が別の変数に割り当てられている場合、その値への参照の数は 1
だけ増加します。逆に、この値への参照を含む変数が別の値を取得すると、この値への参照の数は 1
だけ減ります。
この値への参照の数が 0
になると、この値にアクセスする方法がなくなったことを意味するため、この値が占有しているメモリ領域を再利用できます。こうすることで、次回ガベージ コレクターが実行されるときに、参照がゼロの値によって占められていたメモリが解放されます。
以下の例を見てみましょう。
最後の参照がオブジェクトであるため、最後のフレームでは hobbies
だけがヒープに残ることに注意してください。
サイクル数
参照カウント
このアルゴリズムの問題は、循環参照が考慮されていないことです。これは、1 つ以上のオブジェクトが相互に参照しているが、コードからアクセスできなくなった場合に発生します。
let son = { name: 'John', }; let dad = { name: 'Johnson', } son.dad = dad; dad.son = son; son = null; dad = null;
親オブジェクトは相互に参照しているため、アルゴリズムは割り当てられたメモリを解放せず、両方のオブジェクトにアクセスできなくなります。
これらを null
に設定すると、それらはすべて受信参照を持っているため、参照カウント アルゴリズムはそれらが使用されなくなったことを認識しません。
マーク アンド クリア
マーク アンド クリア アルゴリズムには、循環依存関係に対するソリューションが含まれています。指定されたオブジェクトへの参照を単に計算するのではなく、root
オブジェクトからアクセスできるかどうかを検出します。
ブラウザの root
は window
オブジェクトですが、NodeJS の root
は global
です。
このアルゴリズムは、到達不能なオブジェクトをガベージとしてマークし、スキャン (収集) します。ルート オブジェクトは決して収集されません。
これにより、循環依存関係は問題なくなります。前の例では、dad
オブジェクトも son
オブジェクトもルートからアクセスできません。したがって、それらはすべてガベージとしてマークされ、収集されます。
このアルゴリズムは、2012 年以降、すべての最新のブラウザーに実装されています。パフォーマンスと実装のみが改善されていますが、アルゴリズムの核となる考え方は同じままです。
トレードオフ
自動ガベージ コレクションにより、メモリ管理に時間を無駄にすることなく、アプリケーションの構築に集中できるようになります。ただし、トレードオフもあります。
メモリ使用量
アルゴリズムはメモリがいつ必要でなくなるかを正確に認識できないため、JS アプリケーションは実際に必要なメモリよりも多くのメモリを使用する可能性があります。
オブジェクトがガベージとしてマークされている場合でも、割り当てられたメモリをいつ収集するかどうかはガベージ コレクタによって決定されます。
如果你希望应用程序尽可能提高内存效率,那么最好使用低级语言。 但是请记住,这需要权衡取舍。
性能
收集垃圾的算法通常会定期运行以清理未使用的对象。
问题是我们开发人员不知道何时会回收。 收集大量垃圾或频繁收集垃圾可能会影响性能。然而,用户或开发人员通常不会注意到这种影响。
内存泄漏
在全局变量中存储数据,最常见内存问题可能是内存泄漏。
在浏览器的 JS 中,如果省略var
,const
或let
,则变量会被加到window
对象中。
users = getUsers();
在严格模式下可以避免这种情况。
除了意外地将变量添加到根目录之外,在许多情况下,我们需要这样来使用全局变量,但是一旦不需要时,要记得手动的把它释放了。
释放它很简单,把 null
给它就行了。
window.users = null;
被遗忘的计时器和回调
忘记计时器和回调可以使我们的应用程序的内存使用量增加。 特别是在单页应用程序(SPA)中,在动态添加事件侦听器和回调时必须小心。
被遗忘的计时器
const object = {}; const intervalId = setInterval(function() { // 这里使用的所有东西都无法收集直到清除`setInterval` doSomething(object); }, 2000);
上面的代码每2秒运行一次该函数。 如果我们的项目中有这样的代码,很有可能不需要一直运行它。
只要setInterval
没有被取消,则其中的引用对象就不会被垃圾回收。
确保在不再需要时清除它。
clearInterval(intervalId);
被遗忘的回调
假设我们向按钮添加了onclick
侦听器,之后该按钮将被删除。旧的浏览器无法收集侦听器,但是如今,这不再是问题。
不过,当我们不再需要事件侦听器时,删除它们仍然是一个好的做法。
const element = document.getElementById('button'); const onClick = () => alert('hi'); element.addEventListener('click', onClick); element.removeEventListener('click', onClick); element.parentNode.removeChild(element);
脱离DOM引用
内存泄漏与前面的内存泄漏类似:它发生在用 JS 存储DOM
元素时。
const elements = []; const element = document.getElementById('button'); elements.push(element); function removeAllElements() { elements.forEach((item) => { document.body.removeChild(document.getElementById(item.id)) }); }
删除这些元素时,我们还需要确保也从数组中删除该元素。否则,将无法收集这些DOM元素。
const elements = []; const element = document.getElementById('button'); elements.push(element); function removeAllElements() { elements.forEach((item, index) => { document.body.removeChild(document.getElementById(item.id)); elements.splice(index, 1); }); }
由于每个DOM元素也保留对其父节点的引用,因此可以防止垃圾收集器收集元素的父元素和子元素。
总结
在本文中,我们总结了 JS 中内存管理的核心概念。写这篇文章可以帮助我们理清一些我们不完全理解的概念。
希望这篇对你有所帮助,我们下期再见,记得三连哦!
原文地址:https://felixgerschau.com/javascript-memory-management/
作者:Ahmad shaded
译文地址:https://segmentfault.com/a/1190000037651993
更多编程相关知识,请访问:编程入门!!
以上がJavaScriptのメモリ管理を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

CおよびJavaScriptは、WebAssemblyを介して相互運用性を実現します。 1)CコードはWebAssemblyモジュールにコンパイルされ、JavaScript環境に導入され、コンピューティングパワーが強化されます。 2)ゲーム開発では、Cは物理エンジンとグラフィックスレンダリングを処理し、JavaScriptはゲームロジックとユーザーインターフェイスを担当します。

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

SAP NetWeaver Server Adapter for Eclipse
Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

VSCode Windows 64 ビットのダウンロード
Microsoft によって発売された無料で強力な IDE エディター

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

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

Safe Exam Browser
Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。
