Node.js でメモリ リークをチェックするにはどうすればよいですか?次の記事では、Nodejs のヒープ割り当てについて説明し、ヒープ割り当てを最小限に抑えてメモリ リークを防ぐ方法を紹介します。
#メモリ管理の問題は、コンピュータ分野で常に大きな注目を集めてきました。コンピュータ上で実行される各ソフトウェアには、コンピュータの限られたメモリのごく一部が割り当てられます。このメモリは慎重に管理し、適切なタイミングで割り当てまたは解放する必要があります。
Nodejs
は、効率的な自動ガベージ コレクション メカニズムを通じてメモリ管理の退屈なタスクを処理できるため、開発者は他のタスクに取り組むことができます。 Nodejs
は開発者がメモリ管理の問題を解決するのに役立ちましたが、大規模なアプリケーションを開発する過程では、開発者が V8
と Nodejs
を理解するのは困難です。のメモリ管理メカニズムは依然として非常に重要です。
この記事では、主にヒープ内のメモリの割り当てと解放の方法を紹介し、ヒープの割り当てを最小限に抑えてメモリ リークを防ぐ方法を理解するのに役立ちます。 [関連チュートリアルの推奨事項: nodejs ビデオ チュートリアル 、プログラミング教育 ]
Nodejs でのヒープ割り当て
JavaScript
と Node.js
は多くのことを抽象化し、ほとんどの重労働を舞台裏で実行します。
コードの一部が実行されると、コード内の変数とオブジェクトがスタック メモリまたはヒープ メモリに保存されることがわかっています。JavaScript
コードは、次のコードに保存されます。実行コンテキスト内で実行されます。
ECMAScript
仕様自体は、メモリの割り当てと管理の方法を指定していません。これは、JavaScript
エンジンと基盤となるシステム アーキテクチャに依存する実装の詳細です。エンジンが変数を処理する方法についての深い理解はこの記事の範囲を超えていますが、V8
がどのようにこれを行うかについて詳しく知りたい場合は、記事JavaScript メモリ モデルを参照してください。
と データが V8 JS エンジン メモリにどのように保存されるかを明らかにしますか?
。
Node.js でヒープ メモリの効率的な使用が重要な理由
?
ヒープに格納されたメモリ変数は、削除されたりしない限り常に存在します。ガベージコレクターによって解放されます。ヒープ メモリは、割り当てられて解放された後もこの状態が維持される、大きな連続したメモリ ブロックです。
残念ながら、ヒープ メモリの収集および解放の方法が原因で、メモリが無駄になり、リークが発生する可能性があります。
V8
は世代別ガベージ コレクション メカニズムを使用します。つまり、オブジェクトを異なる世代 (新世代と旧世代) に分割します。世代空間はさまざまな領域に分割されます。たとえば、新世代は新しい空間で構成され、古い世代は古い空間、マッピング空間、ラージ オブジェクト空間に分割されます。新しいオブジェクトは最初に若い世代のスペースに割り当てられ、若い世代のスペースが使い果たされると、ガベージ コレクターがクリーンアップ メカニズムを実行してスペースを解放します。 1 回の GC
実行で生き残ったオブジェクトは若い世代の中央にコピーされ、2 回目の実行で生き残ったオブジェクトは古い世代に移動されます。
実行中のプログラムは最初にメモリを収集し、貴重な仮想メモリ リソースを占有するため、メモリが不要になった場合、プログラムはメモリを解放する必要があります。これがメモリ解放です。
さらに、メモリが解放されると (以前に解放されたヒープの場所に関係なく)、ヒープ メモリは連続したメモリ ブロックにマージされます。ヒープ メモリの複雑さが増すため、ここに保存するとパフォーマンスのオーバーヘッドが高くなります (ただし、後続のストアでは柔軟性が高まります)。
Nodejs
には効率的なガベージ コレクション メカニズムがありますが、ヒープ メモリの非効率的な使用によりメモリ リークが発生する可能性があります。アプリケーションがメモリを過剰に消費したり、クラッシュしたりする可能性があります。
Nodejs ヒープ メモリ リークの原因
ガベージ コレクターは孤立したメモリ領域を探して解放しますが、すべてのメモリを追跡できない場合があります。これは、特に大規模なアプリケーションの場合、不必要な負荷の増加につながる可能性があります。 Nodejs
でガベージ コレクターがどのように動作するかについては、後ほど詳しく説明します。
メモリ リークの最も一般的な原因には次のものがあります。
- 複数の参照
- グローバル変数
- クロージャ
- タイマー
- イベント
複数使用です変数ポインタを介してオブジェクトへの参照を保持する非常に一般的な操作です。これは非常に便利ですが、オブジェクトへの参照の 1 つがガベージ コレクターによって収集され、他の参照が収集されない場合、メモリ リークが発生する可能性もあります。
Node.js
および JavaScript
アプリケーションでは、クリーンアップを忘れられたタイマーとコールバック関数も、メモリ リークの一般的な 2 つの原因です。タイマーにバインドされたオブジェクトは、タイムアウトになるまでガベージ コレクションされません。タイマーが永久に実行されると、参照されたオブジェクトはガベージ コレクターによって収集されなくなります。これは、変数ポインタがオブジェクトを参照していない場合でも発生し、ヒープ内でメモリ リークが発生します。
サンプル コードについて考えてみましょう:
const language = () => { console.log("Javascript");】 // 递归自身 setTimeout(() => language(), 1000); }
上記のコードは常に実行され、ガベージ コレクターによってリサイクルされることはありません
調べ方## メモリ#Nodejs
#Nodejs でのメモリ リークの検出とデバッグに使用できるツールがいくつかあります。 ノード
のプロセス。 memoryUsage API
および AppSignal
のガベージ コレクター ダッシュボード。 Chrome DevTools の使用
Chrome DevToolsおそらく最も簡単なツールの 1 つです。デバッガーを開始するには、
Node を inspect
モードで開始する必要があります。これを行うには、node --inspect
を実行します。 より具体的には、
Node
への入り口が
である場合、node --inspect app.js
を実行して、ノードアプリケーションをデバッグします。次に、Chromium
ブラウザを開き、「chrome://inspect
」と入力します。 Edge://inspect でインスペクター ページを開くこともできます。インスペクター ページには、次のようなページが表示されます。
Node アプリケーションがインスペクター ページの下部に表示されることに注意してください。 。
をクリックしてデバッガーを開きます。デバッガーには 2 つの重要なタブ (Memory
と Profiler
) がありますが、この説明では Memory
タブに焦点を当てます。
Chrome デバッガの使用メモリ リークを見つける最も簡単な方法は、
を使用することです。スナップショットは、いくつかの変数を検査したり、その予約サイズを確認したりするのに役立ちます。 複数のスナップショットを比較することでメモリ リークを見つけることもできます。メモリ リークの前後のスナップショットを保存し、その 2 つを比較するとよいでしょう。スナップショットを取得するには、
ヒープ スナップショット
を 1 回クリックしてから、*スナップショットの取得
ボタンをクリックします。アプリケーションの Total JS ヒープ サイズによっては、これには時間がかかる場合があります。
DevTool の下部にある load
ボタンをクリックして、既存のスナップショットをロードすることもできます。 2 つ以上のスナップショットがある場合、ヒープ割り当てを簡単に比較し、メモリ リークの原因を見つけることができます。スナップショットは次の方法で表示できます。
- summary
: コンストラクター名に基づいてアプリケーション内の Node
オブジェクトは次のとおりです。グループで表示
比較-
: 2つのスナップショットの違いを表示
Containment : ヒープ内を調べ、グローバル名前空間で参照されるオブジェクトを分析できます
統計-
:
ヒープ アナライザーには 2 つの注目すべき列があります - つまり
および
保持サイズ 。
Shallow Size
Retained Size は、当該オブジェクトおよび依存オブジェクトが解放されるかルートノードからアクセスできなくなったときに解放されるメモリサイズです。
Chrome DevTools
はヒープ スナップショットを取得する唯一の方法ではありません。 nodejs
node --heapsnapshot-signal コマンドを実行することもできます:
node --heapsnapshot-signal=SIGUSR2 app.js
任意のフラグを使用できますが、ユーザー定義信号
SIGUSR1 または
SIGUSR2 を使用することをお勧めします。 サーバー上で実行されているアプリケーションからペアのスナップショットを取得する場合は、
V8 パッケージの
writeHeapSnapshot
require("v8").writeHeapSnapshot();
这个方法要求 Nodejs
的版本高于 11.13。在早期的版本中,你可以使用相关的包来实现。
使用 Chrome DevTools
获取堆快照并不是调试内存问题的唯一方法。你也可以使用Allocation instrumentation on timeline
跟踪每个堆分配的情况。
内存分配时间轴显示了随时间变化的测量内存分配的情况。要启用此功能,需要先启动分析器(Profiler
),然后运行应用程序示例以开始调试内存问题。如果你希望记录长时间运行的内存分配操作,并想要更小的性能开销,那么最好的选择是分配抽样方法。
通过 Node
的 process.memoryUsage
API
你也可以使用 Node
的 process.memoryUsage
API来观察内存使用情况。运行 process.memoryUsage
,你可以访问以下内容:
-
rss
:已分配的内存量 -
heapTotal
:已分配堆的总大小 -
heapUsed
:当执行进程时被使用内存总量 -
arrayBuffers
:为 Buffer 实例分配的内存大小
使用 AppSignal
的垃圾收集器看板
为了可视化堆的变化情况,AppSignal
提供了一个方便的垃圾收集看板。当你将 Node.js
应用连接到AppSignal
时,这个看板会自动为你生成!
看看这个例子,在“V8 Heap Statistics
”图表中,你可以清楚地看到内存使用的峰值:
如果看板中中的数据出现一个稳定增长的趋势,这意味着你的代码中或者依赖中存在内存泄漏的情况。
垃圾回收机制工作原理
如果你知道如何发现内存泄漏,但如何修复它们?我们可能很快就知道。但是首先重要的是理解 Nodejs
和 V8
是如何进行垃圾收集的。
垃圾回收机制会在不需要的时候释放内存。为了更高效的工作,垃圾回收算法必须正确的定义和识别不需要再内存中继续存储的内容。
在引用计数 GC
算法中,如果堆中的对象在堆栈中不再有引用,则该对象将被垃圾收集。该算法通过计数引用来工作——因此,如果引用计数为零,则对象将进行垃圾收集。尽管这个算法大多数时候都有效,但它在处理循环引用的情况时却失效了。
看一下代码示例:
let data = {}; data.el = data; let obj1 = {}; let obj2 = {}; obj1.a = obj2; obj2.a = obj1;
具有循环引用的对象永远不会被清除作用域或被垃圾回收器回收,即使不再需要或使用它们。这会形成内存泄漏,并使应用程序效率低下。值得庆幸的是,Node.js
不再使用这种算法进行垃圾回收。
JavaScript
中的最上层对象是一个全局对象。在浏览器中,是 window
对象,但在 Nodejs
中,是 global
对象。该算法比引用计数算法更高效,并解决了循环引用的问题。
考虑到上面的例子,虽然 obj1
和 obj2 仍然
存在循环引用,但如果它们不再从顶级对象可访问(不再需要),它们将被垃圾收集。
这种算法,通常称为 mark and sweep
(标记清除算法)回收算法,非常有用。但是,你必须小心并显式地使一个对象从根节点不可访问,以确保它被垃圾收集。
修复 Nodejs App 中的内存泄漏
这有一些方法可以提高内存使用率并避免内存泄漏。
避免全局变量
全局变量包括使用 var
关键字声明的变量、this
关键字声明的变量和未使用关键字声明的变量。
我们已经偶然声明的全局变量(以及任何其他形式的全局变量)会导致内存泄漏。它们总是可以从全局对象访问,因此除非显式地设置为 null
,否则不能被垃圾收集。
考虑下面的例子:
function variables() { this.a = "Variable one"; var b = "Variable two"; c = "Variable three"; }
这三个变量都是全局变量。为了避免使用全局变量,可以考虑在文件顶部添加 use strict
指令来切换strict
模式。
使用 JSON.parse
JSON
的语法比 JavaScript
简单得多,因此它比 JavaScript
对象更容易解析。
事实上,如果你使用一个大型 JavaScript
对象,通过将其转化为字符串形式,使用时解析为 JSON
,那么你可以在 V8
和Chrome
中将性能提高 1.7 倍。
在其他 JavaScript
引擎(如Safari
)中,性能可能会更好。在 Webpack
中使用这种优化方法来提高前端应用程序的性能。
例如,不使用以下 JavaScript
对象:
const Person = { name: "Samuel", age: 25, language: "English" };
更有效的方法是将它们进行字符串化,然后将其解析为JSON
。
const Person = JSON.parse('{"name":"Samuel","age":25,"language":"English"}');
将大数据处理拆分为块并创建子进程
你获取在实际业务中会当处理大型数据时,遇到一些奇观的内存溢出的问题,例如大的 CSV
文件。当然,你可以通过扩展你的应用内存上限去处理任务,但是最好的方法是通过将大块数据分割为多个小块(chunks
)。
在一些情况下,在多核机器上扩展 Node.js
应用程序可能会有所帮助。这涉及到将应用程序分离为主进程和工作进程。worker
处理繁重的逻辑,而 master
控制 worker
并在内存耗尽时重新启动它们。
有效使用计时器
我们创建的计时器可能会造成内存泄漏。为了提高堆内存管理,确保你的计时器不会永远运行。
特别是,使用 setInterval
创建计时器时,当不再需要计时器时调用 clearInterval
清除计时器是至关重要的。
当你不再需要使用 setTimeout
或 setimmediation
创建计时器时,调用 clearTimeout
或clearImmediate
也是一个很好的实践。
const timeout = setTimeout(() => { console.log("timeout"); }, 1500); const immediate = setImmediate(() => { console.log("immediate"); }); const interval = setInterval(() => { console.log("interval"); }, 500); clearTimeout(timeout); clearImmediate(immediate); clearInterval(interval);
移除闭包中不在需要的变量
在 JavaScript
中,闭包是一个常见概念。例如存在函数嵌套或者回调函数。如果在函数中使用了一个变量,当函数返回时,它将被标记为垃圾收集,但闭包可不是这样的。
代码示例:
const func = () => { let Person1 = { name: "Samuel", age: 25, language: "English" }; let Person2 = { name: "Den", age: 23, language: "Dutch" }; return () => Person2; };
上面函数会一直引用父级作用域并将每个变量保存在作用域中。换句话说,虽然你仅仅使用了 Person2
,但 Person1
和 Person2
都被保存在作用域中。
这会消耗更多内存,并造成内存泄漏。为此,在面临上面这种情况时,你最好仅声明你需要的,将不需要的重置为 null
。
例如:
const func = () => { let Person1 = { name: "Samuel", age: 25, language: "English" }; let Person2 = { name: "Den", age: 23, language: "Dutch" }; Person1 = null; return () => Person2; };
取消订阅观察者和 Event Emitters
具有较长生命周期的观察器和事件发射器可能是内存泄漏的来源,特别是如果你在不再需要它们时没有取消订阅的话。
代码示例:
const EventEmitter = require("events").EventEmitter; const emitter = new EventEmitter(); const bigObject = {}; //Some big object const listener = () => { doSomethingWith(bigObject); }; emitter.on("event1", listener);
在这里,我们保留 bigObject
的内存,直到侦听器从发射器中释放,或者发射器被垃圾收集。为了解决这个问题,我们需要调用 removeEventListener
从发射器中释放监听器。
emitter.removeEventListener("event1", listener);
当连接到发射器的事件侦听器超过 10 个时,也可能发生内存泄漏。大多数情况下,你可以通过编写更高效的代码来解决这个问题。
但是,在某些情况下,你可能需要显式地设置最大事件侦听器。
例如:
emitter.setMaxListeners(n);
总结
在这篇文章中,我们探索了如何最小化你的堆和检测 Node.js
中的内存泄漏。
我们首先研究了 Node
中的堆分配,包括堆栈和堆的工作方式。然后,我们考虑了跟踪内存使用情况和内存泄漏的原因的重要性。
接下来,我们看到了如何使用 Chrome DevTools ,
Node
的进程来查找内存泄漏。memoryUsage
API和 AppSignal
的垃圾收集可视化看板。
最后,我们发现了垃圾收集是如何工作的,并分享了一些修复应用程序内存泄漏的方法。
他のプログラミング言語と同様、JavaScript
と Node.js
ではメモリ管理が非常に重要です。この紹介がお役に立てば幸いです。コーディングを楽しんでください!
元のリンク: Node.js でのヒープ割り当ての最小化
ノード関連の知識について詳しくは、こちらをご覧ください。 nodejs チュートリアル にアクセスしてください!
以上がヒープ割り当てを最小限に抑え、メモリ リークを防ぐ方法を学習するノードの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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

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

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

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます


ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

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

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

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

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

DVWA
Damn Vulnerable Web App (DVWA) は、非常に脆弱な PHP/MySQL Web アプリケーションです。その主な目的は、セキュリティ専門家が法的環境でスキルとツールをテストするのに役立ち、Web 開発者が Web アプリケーションを保護するプロセスをより深く理解できるようにし、教師/生徒が教室環境で Web アプリケーションを教え/学習できるようにすることです。安全。 DVWA の目標は、シンプルでわかりやすいインターフェイスを通じて、さまざまな難易度で最も一般的な Web 脆弱性のいくつかを実践することです。このソフトウェアは、
