ホームページ > ウェブフロントエンド > フロントエンドQ&A > JavaScriptにはGCがあるのでしょうか?

JavaScriptにはGCがあるのでしょうか?

青灯夜游
リリース: 2021-10-09 16:59:41
オリジナル
2851 人が閲覧しました

JavaScriptにはGC(ガベージコレクション機構)というものがあります。 JavaScript はガベージ コレクション機構を使用する言語であり、コード実行時に実行環境がメモリを管理し、ガベージ オブジェクト (参照されていないオブジェクト) をメモリから自動的に破棄します。

このチュートリアルの動作環境: Windows7 システム、JavaScript バージョン 1.8.5、Dell G3 コンピューター。

JavaScript のガベージ コレクション メカニズム (GC)

ガベージ コレクション関連の概念

① とははガベージです

使用されていない (参照されていない) オブジェクトは ガベージです。

② ガベージ コレクションとは

参照されていないオブジェクトを破棄してメモリを解放する、これが ガベージ コレクションです。

C や C などのプログラミング言語では、手動のガベージ コレクションが必要です。

Java、JavaScript、PHP、Python、その他の言語の自動ガベージ コレクション。

JS には自動ガベージ コレクション メカニズムがあり、これらのガベージ オブジェクトをメモリから自動的に破棄します。ガベージ コレクション操作は必要なく、実行することもできません。必要なのは、使用されなくなったオブジェクトを null に設定することだけです。

ガベージ コレクションが必要な理由

  • C/C では、メモリ使用量の追跡とメモリ管理は開発者にとって大きな負担です
    • JavaScript は、ガベージ コレクション メカニズム。これは、コードの実行時に実行環境がメモリを管理する責任を負い、開発者がこの負担を軽減できるようにすることを意味します。
    • 自動メモリ管理を通じてメモリ割り当てとリソースのリサイクルを実現します
    • 基本的な考え方は非常に単純です。どの変数が使用されなくなるかを判断し、そのメモリ領域を解放します。
    • このプロセスは周期的です。つまり、ガベージ コレクション プログラムが時々実行されることになります。
  • JS のオブジェクト、文字列、およびオブジェクトのメモリは固定されていません。メモリは実際に使用されるときにのみ動的に割り当てられます。
    • これらのメモリは、後で解放する必要があります。再使用できるように使用中です。そうしないと、コンピュータの使用可能なメモリが使い果たされた後にクラッシュが発生します。
  • ブラウザ開発の歴史における主なガベージ コレクション メソッドは、
      です。
    • リファレンスカウント方法
    • マーククリア方法

リファレンスカウント方法

アイデア

  • 変数は値のみを参照します
  • 変数が値を参照する場合、参照数は 1
  • 変数への参照が上書きまたはクリアされた場合、参照数 -1
  • 参照数が 0 の場合、このメモリは安全に解放できます。
let arr = [1, 0, 1]   // [1, 0, 1]这块内存被arr引用  引用次数为1
arr = [0, 1, 0]  // [1, 0, 1]的内存引用次数为0被释放  
                 // [0, 1, 0]的内存被arr引用   引用次数为1
const tmp = arr  // [0, 1, 0]的内存被tmp引用   引用次数为2
ログイン後にコピー

循環参照の問題

Netscape Navigator 3.0 は

  • を採用この例では、ObjectA と ObjectB のプロパティがそれぞれ相互参照しています。
  • その結果、この関数実行後、Object の参照回数が 0 にならず、通常の GC に影響を及ぼします。
  • 複数回実行すると、重大なメモリ リークが発生します。
  • マークアンドクリア方式ではこの問題は発生しません。
function Example(){

    let ObjectA = new Object();
    let ObjectB = new Object();

    ObjectA.p = ObjectB;
    ObjectB.p = ObjectA;   

}

Example();
ログイン後にコピー
  • 解決策: 関数の最後で null を指すようにします
ObjectA = null;
ObjectB = null;
ログイン後にコピー

マーククリアメソッド

##循環参照によって引き起こされるメモリ リークの問題を解決するために、Netscape Navigator 4.0 はマーク アンド クリア メソッドを使用し始めました。

2008 年までに、IE、 Firefox、Opera、Chrome、Safari はどちらも JavaScript 実装でマークアップ クリーニング (またはその亜種) を使用しており、ガベージ コレクションを実行する頻度のみが異なります。

アイデア

  • 変数が実行コンテキストに入るときに「エントリ」マークをマークします
  • 同時に、変数が実行コンテキストから離れるとき "leave" をマークします。
    • 今後、この変数にアクセスできなくなります
    • 次回のガベージ コレクション中にメモリが解放されます
function Example(n){
    const a = 1, b = 2, c = 3;
    return n * a * b * c;
}
// 标记Example进入执行上下文

const n = 1;  // 标记n进入执行上下文
Example(n);   // 标记a,b,c进入执行上下文
console.log(n); // 标记a, b, c离开执行上下文,等待垃圾回收
ログイン後にコピー

const と let ステートメントでパフォーマンスを向上させる

  • const と let は、コード スタイルの改善だけでなく、ガベージ コレクションのパフォーマンスの改善にも役立ちます
  • const で JS を作成する ブロック レベル スコープでは、ブロック レベル スコープが関数スコープよりも早く終了する場合、ガベージ コレクション プログラムがより早く介入します。
  • 回復されたメモリをできるだけ早くリサイクルして、メモリを改善します。ガベージ コレクションのパフォーマンス

V8 エンジンのガベージ コレクション

#V8 エンジンのガベージ コレクションには、マークアンドスイープ方式と世代別収集方式

新世代と旧世代に分かれる

新世代

##新世代ガベージ コレクションは
Scavenge

アルゴリズムを採用

共有メモリと新たに割り当てられた少量のメモリに割り当て

    メモリ サイズ
  • 32 ビット システム 16M メモリ
    • 64 ビット システム 32M メモリ
    #パーティション
  • 新世代メモリは次の 2 つの領域に分割され、メモリの半分

      From space
    • To space
    実行
  • 実際に実行するのはスペースからのみです

      スペースへはアイドル状態です
    ##スカベンジ# ##アルゴリズム###
    • 当From space内存使用将要达到上限时开始垃圾回收,将From space中的不可达对象都打上标记
    • 将From space的未标记对象复制到To space。
      • 解决了内存散落分块的问题(不连续的内存空间)
      • 相当于用空间换时间。
    • 然后清空From space、将其闲置,也就是转变为To space,俗称反转。
  • 新生代 -> 老生代

    • 新生代存放的是新分配的小量内存,如果达到以下条件中的一个,将被分配至老生代
      • 内存大小达到From space的25%
      • 经历了From space <-> To space的一个轮回

老生代

老生代采用mark-sweep标记清除和mark-compact标记整理

通常存放较大的内存块和从新生代分配过来的内存块

  • 内存大小
    • 32位系统700M左右
    • 64位系统1.4G左右
  • 分区
    • Old Object Space
      • 字面的老生代,存放的是新生代分配过来的内存。
    • Large Object Space
      • 存放其他区域放不下的较大的内存,基本都超过1M
    • Map Space
      • 存放存储对象的映射关系
    • Code Space
      • 存储编译后的代码
  • 回收流程
    • 标记分类(三色标记)
      • 未被扫描,可回收,下面简称1类
      • 扫描中,不可回收,下面简称2类
      • 扫描完成,不可回收,下面简称3类
    • 遍历
      • 采用深度优先遍历,遍历每个对象。
      • 首先将非根部对象全部标记为1类,然后进行深度优先遍历。
      • 遍历过程中将对象压入栈,这个过程中对象被标记为2类
      • 遍历完成对象出栈,这个对象被标记为3类
      • 整个过程直至栈空
    • Mark-sweep
      • 标记完成之后,将标记为1类的对象进行内存释放

  • Mark-compact

    • 垃圾回收完成之后,内存空间是不连续的。

    • 这样容易造成无法分配较大的内存空间的问题,从而触发垃圾回收。

    • 所以,会有Mark-compact步骤将未被回收的内存块整理为连续地内存空间。

    • 频繁触发垃圾回收会影响引擎的性能,内存空间不足时也会优先触发Mark-compact

垃圾回收优化

  • 增量标记
    • 如果用集中的一段时间进行垃圾回收,新生代倒还好,老生代如果遍历较大的对象,可能会造成卡顿。
    • 增量标记:使垃圾回收程序和应用逻辑程序交替运行,思想类似Time Slicing
  • 并行回收
    • 在垃圾回收的过程中,开启若干辅助线程,提高垃圾回收效率。
  • 并发回收
    • 在逻辑程序执行的过程中,开启若干辅助线程进行垃圾回收,清理和主线程没有任何逻辑关系的内存。

内存泄露场景

全局变量

// exm1
function Example(){
    exm = &#39;LeBron&#39;   
}

// exm2
function Example(){
    this.exm = &#39;LeBron&#39;
}
Example()
ログイン後にコピー

未清除的定时器

const timer = setInterval(() => {
    //...
}, 1000)

// clearInterval(timer)
ログイン後にコピー

闭包

function debounce(fn, time) {
  let timeout = null; 
  return function () {
    if (timeout) {
      clearTimeout(timeout);
    }

    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, time);
  };
}

const fn = debounce(handler, 1000); // fn引用了timeout
ログイン後にコピー

未清除的DOM元素引用

const element = {
    // 此处引用了DOM元素
    button:document.getElementById(&#39;LeBron&#39;),
    select:document.getElementById(&#39;select&#39;)
}

document.body.removeChild(document.getElementById(&#39;LeBron&#39;))
ログイン後にコピー

如何检测内存泄漏

这个其实不难,浏览器原带的开发者工具Performance就可以

  • 步骤
    • F12打开开发者工具
    • 选择Performance工具栏
    • 勾选屏幕截图和Memory
    • 点击开始录制
    • 一段时间之后结束录制
  • 结果
    • 堆内存会周期性地分配和释放
    • 如果堆内存的min值在逐渐上升则存在内存泄漏

优化内存使用

1、尽量不在for循环中定义函数

// exm
const fn = (idx) => {
    return idx * 2;
}

function Example(){
    for(let i=0;i<1000;i++){
        //const fn = (idx) => {
        //    return idx * 2;
        // }
        const res = fn(i);
    }
}
ログイン後にコピー

2、尽量不在for循环中定义对象

function Example() {
  const obj = {};
  let res = "";
  for (let i = 0; i < 1000; i++) {
    // const obj = {
    //   a: i,
    //   b: i * 2,
    //   c: i * 3,
    // };
    obj.a = i;
    obj.b = i * 2;
    obj.c = i * 3;
    res += JSON.stringify(obj);
  }
  return res
}
ログイン後にコピー

3、清空数组

arr = [0, 1, 2]
arr.length = 0; // 清空了数组,数组类型不变
// arr = []  // 重新申请了一块空数组对象内存
ログイン後にコピー

【推荐学习:javascript高级教程

以上がJavaScriptにはGCがあるのでしょうか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート