JSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)
javascriptこのコラムでは、ガベージ コレクションのメカニズム、メモリ リーク、クロージャの内容について紹介します。ファストエンド ベンチを見てみましょう。
先頭に書く: これは、javascript 列で主に書き始めようとしているシリーズです。時代の中で、仕事や面接、技術向上のためにフレームワークを使っているとはいえ、JSの基礎知識はおまけであり、学ばなければいけない知識でもあります。車を運転するのに車について詳しく知る必要はなく、車の一般的な使い方をマスターするだけで十分です。しかし、車の知識があれば、同様に、より上手に運転することができます。もちろん、記事は一つの知識だけを語るのではなく、関連する知識が連続してつながっていくのが一般的で、自分の学びを記録しながら、自分の学びを共有し、励まし合いましょう!できれば、「いいね」もお願いします。あなたの「いいね」が更新の励みにもなります。
概要
- 食事時間: 6〜12分
- 難易度: 簡単、走らずに、帰る前に見てください。
JS についても同様です。 。
JS の
ガベージ コレクター は、公園の警備パトロールと同じように、変数を「パトロール」し、関係のない人はすぐに立ち去ることができます。変数が不要になった場合、その変数が占有していたメモリ領域を解放します。このプロセスは ガベージ コレクション
JS と呼ばれます。リサイクル アルゴリズム、参照カウント、およびマークのクリア。
- 参照カウント メソッド参照カウント メソッドは、最も基本的なガベージ コレクション アルゴリズムであり、最新のブラウザで使用されています。装備は撤去されました。参照カウント方法を学ぶ前に、まず
reference という特定の概念を理解する必要があります。これは、現在の変数が指すメモリ アドレスの記述として考えることができ、メモリに似ています。 JS 参照データ型のポインター。概念を理解するために、まずコード行を見てみましょう:
値をvar obj={name:'jack'};复制代码
ログイン後にコピーobj
に対応します。値をに割り当てると、実際には
が作成されます。 Reference 変数を指します。参照カウントは 1、 参照カウントのメカニズムでは、メモリ内の各値は参照カウントobj
関数スコープのライフサイクルは非常に短いことがわかっています. 関数の実行後が実行されると、変数内のメモリ空間は基本的には役に立たない変数です。これらをクリアしないと、メモリのゴミが解放されず、元のメモリを占有したまま解放されないため、に代入すると
になります nullの場合、この変数は無駄なメモリになります このとき
objの参照数は
になります0, そしてそれはガベージコレクションされます. objが占有しているメモリ空間は解放されます
メモリ リークが発生しやすくなります。 . まず、コードの一部と実行結果を見てみましょう:
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码
ログイン後にコピー と ## が確認できます。 #obj2.target##obj1.target には相互参照があります。
obj1.ageが変更されると、
obj1.target.ageと
obj2.target.ageが変更されるためです。も同時に影響を受け、参照カウントが一貫していることを示します。
関数が実行されると、obj1
とobj2
マーククリア方法はまだ有効です。なぜなら
obj1.targetと
obj2.targetの実行が完了しても、参照カウントは
1のままで、関数が実行されたことは明らかですが、このようなものこのような関数が定義されすぎているため、
メモリリークこれも避けられません - デメリット上記の参照カウント方法はすでに明らかなので、ここではマーキングのクリア方法について説明します。そのような問題はありません。判定基準はオブジェクト
に到達できるかどうかなので、主に
マーキングステージとクリアステージ:##の2つのステージに分かれます。 #マーキング フェーズ
ガベージ コレクターはルート オブジェクト (Window オブジェクト) から開始し、到達可能なすべてのオブジェクトをスキャンします。これはいわゆる- reachable
-
クリアフェーズ スキャン中に、ルート オブジェクトが到達できないオブジェクト (unreachable
) は不要とみなされ、ガベージとしてクリアされます
-
现在再来看下上面的代码
function changeName(){ var obj1={}; var obj2={}; obj1.target=obj2; obj2.target=obj1; obj1.age=15; console.log(obj1.target); console.log(obj2.target); } changeName();复制代码
在函数执行完毕之后,函数的声明周期结束,那么现在,从 Window对象
出发, obj1
和 obj2
都会被垃圾收集器标记为不可抵达,这样子的情况下,互相引用的情况也会迎刃而解。
内存泄漏
该释放的内存垃圾没有被释放,依然霸占着原有的内存不松手,造成系统内存的浪费,导致性能恶化,系统崩溃等严重后果,这就是所谓的内存泄漏
闭包
定义与特性
闭包是指有权访问另一个函数作用域中的变量的函数。至于为什么有权访问,主要是因为作用域嵌套作用域,也就是所谓的作用域链,关于作用域链不清楚的可以看我的第一篇博客一文搞懂JS系列(一)之编译原理,作用域,作用域链,变量提升,暂时性死区,就是因为作用域链的存在,所以内部函数才可以访问外部函数中定义的变量 ,作用域链是向外不向内的,探出头去,向外查找,而不是看着锅里,所以外部函数是无法访问内部函数定义的变量的。并且,还有一个特性就是将闭包内的变量始终保持在内存中。
前面的作用域向外不向内,这里就不再做过多解释了,我们主要来看我后面说的特性,那就是闭包内的变量始终保存在内存中
来看一下阮一峰教程当中的一个例子
function f1(){ var n=999; nAdd=function(){n+=1} function f2(){ console.log(n); } return f2; } var result=f1(); //等同于return f2(); result(); // 999 nAdd(); result(); // 1000 nAdd(); result(); // 1000复制代码
ログイン後にコピー从输出结果就可以看得出来,这个变量
n
就一直保存在内存中,那么,为什么会这样子呢,我们现在就来逐步地分析代码① 首先
f1()
作为f2()
的父函数,根据作用域链的规则,nAdd()
方法以及f2()
方法中可以正常访问到n
的值②
f2()
被赋予了一个全局变量,可能这里大家就会开始产生疑惑了,这个f2()
不是好好地定义在了f1()
函数中吗,这不是扯淡吗,那么,先看下面的这句var result=f1();
,这个result
很明显是被赋予了一个全局变量,这应该是没有任何争议的,那么,接着来看这个f1()
,可以看到最后,是一句return f2;
,看到这里,想必大家也已经想明白了,这个f2()
被赋予了一个全局变量③ 已经明白了上面的这一点以后,根据上面垃圾回收机制所提及到的标记清除法,这个
f2()
始终是可以被根对象Window
访问到的,所以 f2 将始终存在于内存之中,而 f2 是依赖于 f1 ,因此 f1 也将始终存在于内存当中,那么,n
的值也就自然始终存在于内存当中啦④ 还有一点需要注意的就是为什么我们可以直接执行
nAdd()
,这是因为在nAdd()
的前面没有使用var
,因此nAdd()
是一个全局函数而不是局部函数所以,闭包的变量会常驻内存,滥用闭包容易造成内存泄漏,特别是在 IE 浏览器下,2020年了,应该没人使用 IE 了吧(小声bb),解决办法就是在退出函数之前,将不使用的局部变量全部删除,这也是上面讲了垃圾回收机制 => 内存泄漏,再讲到闭包的原因,我会尽量将有关联性的知识点一起讲了,也方便大家学习和加深印象。
系列目录
一张纸懂JS系列(1)之编译原理,作用域,作用域链,变量提升,暂时性死区
一张纸搞懂JS系列(2)之JS内存生命周期,栈内存与堆内存,深浅拷贝
一张纸搞懂JS系列(3)之垃圾回收机制,内存泄漏,闭包
相关免费学习推荐:javascript(视频)
以上がJSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

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

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

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

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

人気の記事

ホットツール

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

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

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

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

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

ホットトピック









C++ ラムダ式は、関数スコープ変数を保存し、関数からアクセスできるようにするクロージャーをサポートしています。構文は [キャプチャリスト](パラメータ)->戻り値の型{関数本体} です。 Capture-list は、キャプチャする変数を定義します。[=] を使用してすべてのローカル変数を値によってキャプチャするか、[&] を使用してすべてのローカル変数を参照によってキャプチャするか、[variable1, variable2,...] を使用して特定の変数をキャプチャできます。ラムダ式はキャプチャされた変数にのみアクセスできますが、元の値を変更することはできません。

クロージャは、外部関数のスコープ内の変数にアクセスできる入れ子関数です。その利点には、データのカプセル化、状態の保持、および柔軟性が含まれます。デメリットとしては、メモリ消費量、パフォーマンスへの影響、デバッグの複雑さなどが挙げられます。さらに、クロージャは匿名関数を作成し、それをコールバックまたは引数として他の関数に渡すことができます。

Valgrind は、メモリの割り当てと割り当て解除をシミュレートすることでメモリ リークとエラーを検出します。使用するには、次の手順に従います。 Valgrind をインストールします。公式 Web サイトからオペレーティング システムのバージョンをダウンロードしてインストールします。プログラムをコンパイルする: Valgrind フラグ (gcc-g-omyprogrammyprogram.c-lstdc++ など) を使用してプログラムをコンパイルします。プログラムを分析する: valgrind--leak-check=fullmyprogram コマンドを使用して、コンパイルされたプログラムを分析します。出力を確認します。Valgrind はプログラムの実行後にレポートを生成し、メモリ リークとエラー メッセージを表示します。

メモリ リークは、ファイル、ネットワーク接続、データベース接続などの使用されなくなったリソースを閉じることによって、Go プログラムのメモリを継続的に増加させる可能性があります。弱参照を使用してメモリ リークを防ぎ、強参照されなくなったオブジェクトをガベージ コレクションの対象にします。 go coroutine を使用すると、メモリ リークを避けるために、終了時にコルーチンのスタック メモリが自動的に解放されます。

C++ におけるメモリ リークとは、プログラムがメモリを割り当てたにもかかわらず解放し忘れ、メモリが再利用されなくなることを意味します。デバッグ手法には、デバッガー (Valgrind、GDB など) の使用、アサーションの挿入、メモリ リーク検出ライブラリ (Boost.LeakDetector、MemorySanitizer など) の使用が含まれます。実際のケースを通じてメモリ リークを検出するための Valgrind の使用法を示し、割り当てられたメモリを常に解放する、スマート ポインターを使用する、メモリ管理ライブラリを使用する、定期的なメモリ チェックを実行するなど、メモリ リークを回避するためのベスト プラクティスを提案します。

Java のクロージャを使用すると、外部関数が終了した場合でも、内部関数が外部スコープの変数にアクセスできるようになります。匿名の内部クラスを通じて実装されると、内部クラスは外部クラスへの参照を保持し、外部変数をアクティブに保ちます。クロージャによりコードの柔軟性が向上しますが、匿名の内部クラスによる外部変数への参照により、それらの変数が存続するため、メモリ リークのリスクに注意する必要があります。

Go 言語の関数クロージャは単体テストで重要な役割を果たします。 値のキャプチャ: クロージャは外側のスコープ内の変数にアクセスできるため、テスト パラメータをキャプチャしてネストされた関数で再利用できます。テスト コードの簡素化: クロージャは値をキャプチャすることで、ループごとにパラメーターを繰り返し設定する必要性を排除し、テスト コードを簡素化します。可読性の向上: クロージャを使用してテスト ロジックを整理し、テスト コードをより明確で読みやすくします。

C++ でメモリ リークを見つけるには、Valgrind と AddressSanitizer を利用できます。 Valgrind はリークを動的に検出し、アドレス、サイズ、呼び出しスタックを表示します。 AddressSanitizer は、メモリ エラーとリークを検出する Clang コンパイラ プラグインです。 ASan リーク チェックを有効にするには、コンパイル時に --leak-check=full オプションを使用します。これにより、プログラムの実行後にリークが報告されます。
