자바스크립트에 gc가 있나요?

青灯夜游
풀어 주다: 2021-10-09 16:59:41
원래의
2769명이 탐색했습니다.

자바스크립트에는 GC(가비지 수집 메커니즘)가 있습니다. JavaScript는 가비지 컬렉션 메커니즘을 사용하는 언어입니다. 실행 환경은 코드가 실행될 때 메모리를 관리하고 메모리에서 가비지 개체(참조되지 않는 개체)를 자동으로 삭제합니다.

이 튜토리얼의 운영 환경: Windows 7 시스템, JavaScript 버전 1.8.5, Dell G3 컴퓨터.

JavaScript의 가비지 수집 메커니즘(GC)

가비지 수집과 관련된 개념

① 쓰레기란 무엇입니까

사용되지 않는(참조되는) 객체는 garbage입니다.

② 가비지 컬렉션이란?

참조되지 않은 객체를 파기하고 메모리를 해제하는 것을 가비지 컬렉션이라고 합니다.

C 및 C++와 같은 프로그래밍 언어에는 수동 가비지 수집이 필요합니다.

Java, JavaScript, PHP, Python 및 기타 언어에 대한 자동 가비지 수집.

JS에는 자동 가비지 수집 메커니즘이 있어 이러한 가비지 개체를 메모리에서 자동으로 제거합니다. 우리는 가비지 수집 작업을 수행할 필요도 없고 수행할 수도 없습니다. 우리가 해야 할 일은 더 이상 사용되지 않는 객체를 null로 설정하는 것뿐입니다.

가비지 컬렉션이 필요한 이유

  • C/C++에서 메모리 사용량을 추적하고 메모리를 관리하는 것은 개발자에게 큰 부담입니다.
    • JavaScript는 가비지 컬렉션 메커니즘을 사용하는 언어입니다. 즉, 실행 환경이 메모리 관리를 담당한다는 의미입니다. 코드 실행 중 메모리는 개발자의 부담을 덜어줍니다
    • 자동 메모리 관리를 통해 메모리 할당 및 리소스 재활용을 실현
    • 기본 아이디어는 매우 간단합니다. 어떤 변수가 더 이상 사용되지 않을지 결정하고 해당 메모리 공간을 할당합니다. Release
    • 이 프로세스는 다음과 같습니다. 순환적, 즉 가비지 수집 프로그램이 가끔씩 실행된다는 의미입니다.
  • JS의 객체, 문자열, 객체와 같은 메모리는 고정되지 않고 실제로 사용되는 메모리만 시간이 되면 동적으로 할당됩니다. up
    • 이러한 메모리는 재사용하지 않고 해제해야 합니다. 그렇지 않으면 컴퓨터의 사용 가능한 메모리가 고갈된 후 충돌이 발생합니다
  • 브라우저 개발 역사상 주요 가비지 수집 방법은
    • 참조 계산 방법입니다.
    • 마크 앤 클리어 방법

참조 카운팅 방법

Idea

  • 변수는 값을 참조할 뿐입니다
  • 변수가 값을 참조할 경우 참조 개수 +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의 속성이 각각 서로를 참조합니다.
  • 결과적으로 이 함수가 실행된 후 개체가 참조되는 횟수는 0이 되지 않으며 일반 GC에 영향을 미칩니다.
  • 여러 번 실행하면 심각한 메모리 누수가 발생합니다.
  • 마크 앤 클리어 방식에는 이런 문제가 없습니다.
function Example(){

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

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

}

Example();
로그인 후 복사
  • 해결책: 함수 끝에 null을 지정합니다
ObjectA = null;
ObjectB = null;
로그인 후 복사

mark andclear method

순환 참조로 인한 메모리 누수 문제를 해결하기 위해 Netscape Navigator 4.0에서는 마크 앤 클리어 방법을 사용하세요

2008년까지 IE, Firefox, Opera, Chrome 및 Safari는 모두 JavaScript 구현에서 마크업 정리(또는 그 변형)를 사용했으며 가비지 수집 실행 빈도만 다릅니다.

Idea

  • 실행 컨텍스트에 들어갈 때 변수를 "entering"으로 표시하세요
  • 동시에 실행 컨텍스트를 떠날 때 변수를 "leaving"으로 표시하세요
    • 이제부터 이 변수는 사용할 수 없습니다. Accessed
    • 다음 가비지 컬렉션에서는 필요할 때 메모리가 해제됩니다
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 및 명령문으로 성능을 향상시키세요

  • const를 사용하여 코드 스타일을 개선할 뿐만 아니라 가비지 컬렉션 성능도 향상시키는 데 도움을 줍니다
  • const를 만들고 JS 블록 수준 범위를 만들자. 블록 수준 범위가 함수 범위보다 먼저 끝나면 가비지 수집 프로그램이 더 일찍 개입합니다.
  • 복구된 메모리를 최대한 빨리 재활용하여 가비지 수집 성능을 향상시킵니다

V8 엔진 가비지 수집

V8 엔진의 가비지 수집은 표시 및 스위프 방식과 세대별 수집 방식을 채택합니다

신세대와 구세대로 구분됩니다

신세대

신세대 가비지 컬렉션은 Scavenge< /code> 알고리즘을 사용합니다. 配 작은 메모리와 새로 할당된 적은 양의 메모리 <code>Scavenge 算法

分配给常用内存和新分配的小量内存

  • 内存大小

    • 32位系统16M内存
    • 64位系统32M内存
  • 分区

    • 新生代内存分为以下两区,内存各占一半
    • From space
    • To space
  • 运行

    • 实际运行的只有From space
    • To space处于空闲状态
  • Scavenge

    🎜🎜🎜 메모리 크기 🎜🎜🎜 32비트 시스템 16M 메모리 🎜🎜 64비트 시스템 32M 메모리 🎜 🎜🎜🎜🎜 파티션 🎜🎜🎜 차세대 메모리는 다음 두 영역으로 나누어지며 각각 메모리의 절반을 차지합니다. 실제로 실행 중이며 유휴 상태입니다🎜🎜🎜🎜🎜Scavenge 알고리즘🎜
    • 当From space内存使用将要达到上限时开始垃圾回收,将From space中的不可达对象都打上标记
    • 将From space的未标记对象复制到To space。
      • 解决了内存散落分块的问题(不连续的内存空间)
      • 相当于用空间换时间。
    • 然后清空From space、将其闲置,也就是转变为To space,俗称反转。
  • 新生代 -> 老生代

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

<자바스크립트에 gc가 있나요? src="https://자바스크립트에 gc가 있나요?.php.cn/upload/article/000/000/024/775b02346fd66880393744dbeb1700d0-0.png" alt="자바스크립트에 gc가 있나요?"/>

老生代

老生代采用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类的对象进行内存释放

  • <자바스크립트에 gc가 있나요? src="https://자바스크립트에 gc가 있나요?.php.cn/upload/article/000/000/024/d3ba4d940b89fc82bc25f3869f1b3575-1.png" alt="자바스크립트에 gc가 있나요?"/>

  • Mark-compact

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

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

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

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

<자바스크립트에 gc가 있나요? src="https://자바스크립트에 gc가 있나요?.php.cn/upload/article/000/000/024/d3ba4d940b89fc82bc25f3869f1b3575-2.png" alt="자바스크립트에 gc가 있나요?"/>

垃圾回收优化

  • 增量标记
    • 如果用集中的一段时间进行垃圾回收,新生代倒还好,老生代如果遍历较大的对象,可能会造成卡顿。
    • 增量标记:使垃圾回收程序和应用逻辑程序交替运行,思想类似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值在逐渐上升则存在内存泄漏

<자바스크립트에 gc가 있나요? src="https://자바스크립트에 gc가 있나요?.php.cn/upload/article/000/000/024/0f4033f98face5743238275f0388e49a-3.png" alt="자바스크립트에 gc가 있나요?"/>

优化内存使用

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高级教程

위 내용은 자바스크립트에 gc가 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!