序文: ガベージ コレクションを強制することはできないので、それが機能するかどうかをどうやって確認すればよいのでしょうか。また、ガベージ コレクションについて何がわかっているのでしょうか。 このプロセス中、スクリプトの実行は一時停止されます。 アクセスできないリソースのメモリが解放されます。 非決定論的です。 一度にメモリ全体をチェックするのではなく、複数のサイクルで実行されます。 予測できませんが、必要なときに実行されます。 これは、リソースとメモリの割り当ての問題について心配する必要がないことを意味しますか? もちろん違います。注意しないと、メモリリークが発生する可能性があります。 メモリリークとは何ですか? メモリ リークとは、ソフトウェアが再利用できない割り当てられたメモリのブロックです。 メモリがリークすると、ガベージ コレクターがより頻繁に実行される可能性があります。このプロセスによりスクリプトの実行が妨げられるため、プログラムが停止する可能性があります。停止すると、うるさいユーザーは間違いなくそれに気づき、不満を抱くと、製品はすぐにオフラインになります。さらに深刻なケースでは、アプリケーション全体がクラッシュし、gg になります。 メモリ リークを防ぐにはどうすればよいでしょうか。重要なのは、不要なリソースを保持しないようにすることです。一般的なシナリオをいくつか見てみましょう。 1. タイマー監視
x 回のループ後に完了したことを通知するコールバック関数を呼び出すコンポーネントを作成します。この例では React をインポートし、{useRef} を 'react' から取得します。 const タイマー = ({ cicles, onFinish }) => { 定数 currentCicles = useRef(0); 間隔を設定する(() => { (currentCicles.current >= cicles) の場合 { 終了時に(); 戻る; } currentCicles.current++; }, 500); 戻る ( <div>読み込み中...</div> ); } デフォルトのタイマーをエクスポートします。 一見、問題はないように見えます。心配しないでください。このタイマーをトリガーする別のコンポーネントを作成し、そのメモリ パフォーマンスを分析しましょう。 React をインポートし、{useState} を 'react' から取得します。 '../styles/Home.module.css' からスタイルをインポートします '../components/Timer' から Timer をインポートします。 デフォルト関数 Home() をエクスポートします。 const [showTimer、setShowTimer] = useState(); const onFinish = () => setShowTimer(false); 戻る ( <div className={styles.container}> {表示タイマー? ( <タイマーサイクル={10} onFinish={onFinish} /> ): ( <ボタンのクリック時={() => setShowTimer(true)}> リトライ </ボタン> )} </div> ) } 「再試行」ボタンを数回クリックした後、 「再試行」ボタンをクリックすると、割り当てられるメモリがどんどん増えていくのがわかります。これは、以前に割り当てられたメモリが解放されていないことを意味します。タイマーは交換されずにまだ動作しています。 この問題を解決するにはどうすればよいでしょうか? setInterval の戻り値は間隔 ID であり、これを使用して間隔をキャンセルできます。この特別なケースでは、コンポーネントがアンマウントされた後に 使用効果(() => { 定数intervalId = setInterval(() => { (currentCicles.current >= cicles) の場合 { 終了時に(); 戻る; } currentCicles.current++; }, 500); 戻り値 () => clearInterval(intervalId); }, []) コードを書いているときにこの問題を見つけるのは難しい場合があります。最善の方法は、コンポーネントを抽象化することです。 ここで 'react' から useEffect をインポートします。 エクスポートconst useTimeout = (refreshCycle = 100, コールバック) => { 使用効果(() => { リフレッシュサイクル <= 0 の場合 setTimeout(コールバック、0); 戻る; } 定数intervalId = setInterval(() => { 折り返し電話(); }, リフレッシュサイクル); 戻り値 () => clearInterval(intervalId); }, [リフレッシュサイクル、設定間隔、クリア間隔]); }; デフォルトの useTimeout をエクスポートします。 これで、setInterval を使用する必要があるときはいつでも、次のように実行できます。 const handleTimeout = () => ...; タイムアウトを使用します(100、ハンドルタイムアウト); これで、メモリ リークを心配せずにこの 2. イベント監視
この例では、キーボード ショートカット機能を作成します。ページごとに異なる機能があるため、異なるショートカットキー機能を作成します。 関数 homeShortcuts({ key}) { if (キー === 'E') { console.log('ウィジェットを編集') } } // ユーザーがホームページにログインすると、document.addEventListener('keyup', homeShortcuts); が実行されます。 // ユーザーが何か操作をしてから設定へ移動します function settingsShortcuts({ key}) { if (キー === 'E') { console.log('設定を編集') } } // ユーザーがホームページにログインすると、document.addEventListener('keyup', settingsShortcuts); が実行されます。 2 番目の 以前のコールバックをクリアするには、removeEventListener を使用する必要があります。 document.removeEventListener('keyup', homeShortcuts); 上記のコードをリファクタリングします。 関数 homeShortcuts({ key}) { if (キー === 'E') { console.log('ウィジェットを編集') } } // ユーザーがホームに戻り、 document.addEventListener('keyup', homeShortcuts); // ユーザーが何か操作して設定に移動します 関数設定ショートカット({キー}) { if (キー === 'E') { console.log('設定を編集') } } // ユーザーがホームに戻り、 document.removeEventListener('keyup', homeShortcuts); document.addEventListener('keyup', 設定ショートカット); 原則として、グローバル オブジェクトのツールを使用する場合は十分に注意してください。 3.オブザーバー
強力ではありますが、注意して使用する必要があります。オブジェクトの観察が終わったら、使用していないときは必ずキャンセルしてください。 コードを見てみましょう: const ref = ... const 可視 = (可視) => { console.log(`${visible} です`); } 使用効果(() => { (!参照)の場合{ 戻る; } オブザーバー.current = 新しい IntersectionObserver( (エントリ) => { エントリ[0]が交差している場合 表示される(true); } それ以外 { 可視(false); } }, { ルートマージン: `-${header.height}px` }, ); オブザーバー.current.observe(ref); }, [参照]); 上記のコードは良さそうです。しかし、コンポーネントがアンマウントされると、オブザーバーはどうなるでしょうか? クリアされず、メモリ リークが発生します。 この問題をどうやって解決するのでしょうか? 切断メソッドを使用するだけです: const ref = ... const 可視 = (可視) => { console.log(`${visible} です`); } 使用効果(() => { (!参照)の場合{ 戻る; } オブザーバー.current = 新しい IntersectionObserver( (エントリ) => { エントリ[0]が交差している場合 表示される(true); } それ以外 { 可視(false); } }, { ルートマージン: `-${header.height}px` }, ); オブザーバー.current.observe(ref); 戻り値 () => observer.current?.disconnect(); }, [参照]); 4. ウィンドウオブジェクト
次の例を見てください。 関数 addElement(要素) { if (!this.stack) { this.stack = { 要素: [] } } this.stack.elements.push(要素); } 無害に見えますが、 別の問題としては、グローバル変数を誤って定義している可能性があります。 var a = 'example 1'; // var が作成された場所にスコープが設定されます b = 'example 2'; // Window オブジェクトに追加されます この問題を防ぐには、厳密モードを使用します。 「厳密な使用」 厳密モードを使用すると、 厳密モードが前述の例に与える影響:
キャッチされない参照エラー: b が定義されていません 5. DOM参照を保持するDOM ノードもメモリ リークの影響を受けません。それらへの参照を保存しないように注意する必要があります。そうしないと、まだアクセス可能なため、ガベージ コレクターはそれらをクリーンアップできません。 小さなコード スニペットで説明しましょう。 定数要素 = []; const リスト = document.getElementById('リスト'); 関数addElement() { // クリーンノード リスト.innerHTML = ''; divElement を document.createElement('div') に設定します。 const element = document.createTextNode(`要素 ${elements.length} を追加`); divElement.appendChild(要素); リストに子要素を追加します。 divElement をプッシュします。 } document.getElementById('addElement').onclick = addElement;
次に 関数を数回実行した後、監視します。 上のスクリーンショットでノードがどのようにリークされているかを確認してください。では、これをどのように修正するのでしょうか? 要約: この記事では、最も一般的なタイプのメモリ リークについて説明しました。明らかに、 一般的な 以下もご興味があるかもしれません:
|
<<: Linux でファイル権限を変更する chmod コマンドの詳細な分析
目次序文【ログ取り消し】 【REDOログ】 【バイナリログ】要約する序文MySQL には、REDO ...
Nestjs 例外フィルターといえば、非常に強力な .Net のグローバル フィルターについて触れな...
シナリオの説明あるシステムでは、機能サービスはdocker stack deploy xxxで起動し...
目次簡単な紹介1. 現在のgccバージョンを確認する2. gccインストールパッケージ(バージョン1...
この記事では、シンプルなカレンダー効果を実現するためのjsの具体的なコードを参考までに共有します。具...
目次1. オブジェクトメソッドを定義する2. プロトタイプメソッドを定義する3. イベントコールバッ...
実際、上記の 3 つの表はいずれも 3 行 3 列です。区切り線を非表示にするコツはルールにあります...
ここで 123WORDPRESS.COM はこれらのテンプレートの最初の部分を紹介します。各テンプレ...
HTML5 と jQuery はアップロード前にローカル画像のプレビューを実装しており、その効果は...
Linux システム管理者にとって、サービスがポートに正しくバインドされているか、またはポートをリッ...
目次制御されていないコンポーネント制御コンポーネント知らせ結論は制御されていないコンポーネントフォー...
スプライト:以前は、各画像リソースは独立した画像でした。ブラウザが Web サイト内のさまざまな W...
多くのウェブデザイナーは、ウェブページのレイアウトを設計する際に、インターフェースウェブページの幅に...
目次1. プロキシモジュールをインストールする2. プロキシを設定する1. プロキシモジュールをイン...
この記事では、MySQL 8.0.15 winx64解凍版のインストールと設定方法を紹介します。具体...