>웹 프론트엔드 >JS 튜토리얼 >JavaScript 메모리 관리 및 GC 알고리즘에 대한 심층적인 이해

JavaScript 메모리 관리 및 GC 알고리즘에 대한 심층적인 이해

WBOY
WBOY앞으로
2022-07-26 13:50:322017검색

이 기사에서는 javascript에 대한 관련 지식을 제공합니다. 주로 JavaScript의 가비지 수집 메커니즘과 일반적으로 사용되는 가비지 수집 알고리즘에 대한 심층적인 이해를 소개합니다. 관리, 모두에게 도움이 되길 바랍니다.

JavaScript 메모리 관리 및 GC 알고리즘에 대한 심층적인 이해

[관련 권장 사항: javascript 비디오 튜토리얼, web front-end]

Foreword

JavaScript는 변수(배열, 문자열, 객체 등)를 생성할 때 자동으로 메모리를 할당하지만, 이를 사용하면 할당된 콘텐츠가 "자동으로" 해제됩니다. JavaScript 언어는 C 언어와 같은 다른 저수준 언어와 달리 모든 할당을 위해 malloc()과 같은 메모리 관리 인터페이스를 제공합니다. 필요한 메모리 공간인 free()는 이전에 할당된 메모리 공간을 해제합니다. malloc()用于分配所需的内存空间、free()释放之前所分配的内存空间。

我们将释放内存的过程称为垃圾回收,像JavaScript这种高级语言提供了内存自动分配和自动回收,因为这个自动就导致许多开发者不会去关心内存管理。

即使高级语言提供了自动内存管理,但是我们也需要对内管管理有一下基本的理解,有时候自动内存管理出现了问题,我们可以更好的去解决它,或者说使用代价最小的方法解决它。

内存的生命周期

其实不管是什么语言,内存的声明周期大致分为如下几个阶段:

下面我们对每一步进行具体说明:

  • 内存分配:当我们定义变量时,系统会自动为其分配内存,它允许在程序中使用这块内存。
  • 内存使用:在对变量进行读写的时候发生
  • 内存回收:使用完毕后,自动释放不需要内存,也就是由垃圾回收机制自动回收不再使用的内存

JavaScript中的内存分配

为了保护开发人员的头发,JavaScript在定义变量时就自动完成了内存分配,示例代码如下:

let num = 123 // 给数值变量分配内存
let str = '一碗周' // 给字符串分配内存

let obj = {
  name: '一碗周',
  age: 18,
} // 给对象及其包含的值分配内存

// 给数组及其包含的值分配内存(类似于对象)
let arr = [1, null, 'abc']

function fun(a) {
  return a + 2
} // 给函数(可调用的对象)分配内存

// 函数表达式也能分配一个对象
Element.addEventListener(
  'click',
  event => {
    console.log(event)
  },
  false,
)

有些时候并不会重新分配内存,如下面这段代码:

// 给数组及其包含的值分配内存(类似于对象)
let arr = [1, null, 'abc']

let arr2 = [arr[0], arr[2]]
// 这里并不会重新对分配内存,而是直接存储原来的那份内存

在JavaScript中使用内存

JavaScript中使用值的过程实际上是对分配内存进行读取与写入的操作。这里的读取与写入可能是写入一个变量、读取某个变量的值、写入一个对象的属性值以及为函数传递参数等。

释放内存

JavaScript中的内存释放是自动的,释放的时机就是某些值(内存地址)不在使用了,JavaScript就会自动释放其占用的内存。

其实大多数内存管理的问题都在这个阶段。在这里最艰难的任务就是找到那些不需要的变量。

虽然说现在打高级语言都有自己垃圾回收机制,虽然现在的垃圾回收算法很多,但是也无法智能的回收所有的极端情况,这就是我们为什么要学习内存管理以及垃圾回收算法的理由了。

接下来我们来讨论一下JavaScript中的垃圾回收以及常用的垃圾回收算法。

JavaScript中的垃圾回收

前面我们也说了,JavaScript中的内存管理是自动的,在创建对象时会自动分配内存,当对象不在被引用或者不能从根上访问时,就会被当做垃圾给回收掉。

JavaScript中的可达对象简单的说就是可以访问到的对象,不管是通过引用还是作用域链的方式,只要能访问到的就称之为可达对象。可达对象的可达是有一个标准的,就是必须从根上出发是否能被找到;这里的根可以理解为JavaScript中的全局变量对象,在浏览器环境中就是window、在Node环境中就是global

为了更好的理解引用的概念,看下面这一段代码:

let person = {
  name: '一碗周',
}
let man = person
person = null

图解如下:

根据上面那个图我们可以看到,最终这个{ name: '一碗周' }우리는

메모리를 가비지 수집으로 해제하는 프로세스

라고 합니다. JavaScript와 같은 고급 언어는 자동메모리 할당 및

자동🎜메모리 재활용을 제공합니다. 이러한 자동성 때문에 많은 개발자는 메모리 관리에 신경 쓰지 않습니다. 🎜🎜고급 언어에서 자동 메모리 관리를 제공하더라도 내부 관리에 대한 기본적인 이해가 필요하며 때로는 자동 메모리 관리에 문제가 있을 수 있으며 이를 더 잘 해결하거나 가장 저렴한 방법을 사용할 수 있습니다. 해결하세요. 🎜🎜메모리 수명 주기🎜🎜🎜사실 어떤 언어이든 메모리 선언 주기는 대략 다음 단계로 나뉩니다.🎜🎜

🎜🎜🎜아래에서 각 단계를 자세히 설명하겠습니다.🎜🎜

  • 🎜메모리 할당: 🎜변수를 정의하면 시스템이 자동으로 메모리를 할당하여 프로그램에서 이 메모리를 사용할 수 있습니다.
  • 🎜메모리 사용량: 🎜변수를 읽고 쓸 때 발생 🎜
  • 🎜메모리 재활용: 🎜사용 후 불필요한 메모리는 자동으로 해제됩니다. 즉, 가비지 수집되는 메커니즘입니다. 더 이상 사용하지 않는 메모리를 자동으로 재활용

JavaScript의 메모리 할당

🎜🎜개발자의 머리카락을 보호하기 위해 JavaScript는 변수를 정의할 때 자동으로 메모리 할당을 완료합니다. 코드는 다음과 같습니다. 🎜🎜
function groupObj(obj1, obj2) {
  obj1.next = obj2
  obj2.prev = obj1

  return {
    obj1,
    obj2,
  }
}
let obj = groupObj({ name: '大明' }, { name: '小明' })
🎜🎜다음 코드와 같이 때때로 메모리가 재할당되지 않는 경우가 있습니다. 🎜🎜
delete obj.obj1
delete obj.obj2.prev

JavaScript에서 메모리 사용

🎜JavaScript에서 값을 사용하는 프로세스는 실제로 메모리 읽기 및 쓴다. 여기서 읽고 쓰는 것은 변수 쓰기, 변수 값 읽기, 객체의 속성 값 쓰기, 매개변수를 함수에 전달하는 것 등이 될 수 있습니다. 🎜

메모리 해제

🎜JavaScript의 메모리 해제는 자동으로 수행됩니다. 해제 시점은 특정 값(메모리 주소)이 더 이상 사용되지 않는 시점이며, JavaScript는 해당 값이 차지하는 메모리를 자동으로 해제합니다. 🎜🎜사실 대부분의 메모리 관리 문제는 이 단계에서 발생합니다. 여기서 가장 어려운 작업은 필요하지 않은 변수를 찾는 것입니다. 🎜🎜이제 고급 언어에는 자체 가비지 수집 메커니즘이 있고 가비지 수집 알고리즘이 많지만 모든 극단적인 상황을 지능적으로 재활용할 수는 없습니다. 이것이 바로 우리가 메모리 관리 및 가비지 수집 알고리즘을 배워야 하는 이유입니다. 🎜🎜다음으로 JavaScript의 가비지 수집과 일반적으로 사용되는 가비지 수집 알고리즘에 대해 논의하겠습니다. 🎜🎜JavaScript의 가비지 수집🎜🎜앞서 말했듯이 JavaScript의 메모리 관리는 자동으로 이루어집니다. 객체가 더 이상 참조되지 않거나🎜루트🎜에서 액세스할 수 없으면 메모리가 자동으로 할당됩니다. 쓰레기로 재활용하세요. 🎜🎜JavaScript에서 도달 가능한 객체는 단순히 참조 또는 범위 체인을 통해 액세스할 수 있는 객체입니다🎜. 액세스할 수 있는 한 이를 도달 ​​가능한 객체라고 합니다. 도달 가능한 개체의 도달 가능성에 대한 표준이 있습니다. 즉, 루트에서 시작하여 찾을 수 있는지 여부입니다. 여기서 루트는 브라우저 환경에서 window인 JavaScript의 전역 변수 개체로 이해될 수 있습니다. code>, Node 환경에서는 <code>global입니다. 🎜🎜🎜인용의 개념을 더 잘 이해하려면 다음 코드를 살펴보세요. 🎜🎜
// { name: &#39;一碗周&#39; } 的引用计数器 + 1
let person = {
  name: &#39;一碗周&#39;,
}
// 又增加了一个引用,引用计数器 + 1
let man = person
// 取消一个引用,引用计数器 - 1
person = null
// 取消一个引用,引用计数器 - 1。此时 { name: &#39;一碗周&#39; } 的内存就会被当做垃圾回收
man = null
🎜🎜도표는 다음과 같습니다. 🎜🎜

🎜🎜위 그림을 보면 결국 이 { name: 'A Bowl of Zhou' } 아직 참조가 있으므로 가비지로 수집되지 않습니다. 🎜🎜🎜이제 도달 가능한 객체를 이해해 보겠습니다. 코드는 다음과 같습니다. 🎜🎜

function groupObj(obj1, obj2) {
  obj1.next = obj2
  obj2.prev = obj1

  return {
    obj1,
    obj2,
  }
}
let obj = groupObj({ name: &#39;大明&#39; }, { name: &#39;小明&#39; })

调用groupObj()函数的的结果obj是一个包含两个对象的一个对象,其中obj.obj1next属性指向obj.obj2;而obj.obj2prev属性又指向obj.obj2。最终形成了一个无限套娃。

如下图:

现在来看下面这段代码:

delete obj.obj1
delete obj.obj2.prev

我们删除obj对象中的obj1对象的引用和obj.obj2中的prev属性对obj1的引用。

图解如下:

此时的obj1就被当做垃圾给回收了。

GC算法

GC是Garbage collection的简写,也就是垃圾回收。当GC进行工作的时候,它可以找到内存中的垃圾、并释放和回收空间,回收之后方便我们后续的进行使用。

在GC中的垃圾包括程序中不在需要使用的对象以及程序中不能再访问到的对象都会被当做垃圾。

GC算法就是工作时查找和回收所遵循的规则,常见的GC算法有如下几种:

  • 引用计数:通过一个数字来记录引用次数,通过判断当前数字是不是0来判断对象是不是一个垃圾。
  • 标记清除:在工作时为对象添加一个标记来判断是不是垃圾。
  • 标记整理:与标记清除类似。
  • 分代回收:V8中使用的垃圾回收机制。

引用计数算法

引用计数算法的核心思想就是设置一个引用计数器,判断当前引用数是否为0 ,从而决定当前对象是不是一个垃圾,从而垃圾回收机制开始工作,释放这块内存。

引用计数算法的核心就是引用计数器 ,由于引用计数器的存在,也就导致该算法与其他GC算法有所差别。

引用计数器的改变是在引用关系发生改变时就会发生变化,当引用计数器变为0的时候,该对象就会被当做垃圾回收。

现在我们通过一段代码来看一下:

// { name: &#39;一碗周&#39; } 的引用计数器 + 1
let person = {
  name: &#39;一碗周&#39;,
}
// 又增加了一个引用,引用计数器 + 1
let man = person
// 取消一个引用,引用计数器 - 1
person = null
// 取消一个引用,引用计数器 - 1。此时 { name: &#39;一碗周&#39; } 的内存就会被当做垃圾回收
man = null

引用计数算法的优点如下:

  • 发现垃圾时立即回收;
  • 最大限度减少程序暂停,这里因为发现垃圾就立刻回收了,减少了程序因内存爆满而被迫停止的现象。

缺点如下:

  • 无法回收循环引用的对象;

就比如下面这段代码:

function fun() {
  const obj1 = {}
  const obj2 = {}
  obj1.next = obj2
  obj2.prev = obj1
  return &#39;一碗周&#39;
}
fun()

上面的代码中,当函数执行完成之后函数体的内容已经是没有作用的了,但是由于obj1obj2都存在不止1个引用,导致两种都无法被回收,就造成了空间内存的浪费。

  • 时间开销大,这是因为引用计数算法需要时刻的去监控引用计数器的变化。

标记清除算法

标记清除算法解决了引用计数算法的⼀些问题, 并且实现较为简单, 在V8引擎中会有被⼤量的使⽤到。

在使⽤标记清除算法时,未引用对象并不会被立即回收.取⽽代之的做法是,垃圾对象将⼀直累计到内存耗尽为⽌.当内存耗尽时,程序将会被挂起,垃圾回收开始执行.当所有的未引用对象被清理完毕 时,程序才会继续执行.该算法的核心思想就是将整个垃圾回收操作分为标记和清除两个阶段完成。

第一个阶段就是遍历所有对象,标记所有的可达对象;第二个阶段就是遍历所有对象清除没有标记的对象,同时会抹掉所有已经标记的对象,便于下次的工作。

为了区分可用对象与垃圾对象,我们需要在每⼀个对象中记录对象的状态。 因此, 我们在每⼀个对象中加⼊了⼀个特殊的布尔类型的域, 叫做marked。 默认情况下, 对象被创建时处于未标记状态。 所以, marked 域被初始化为false

进行垃圾回收完毕之后,将回收的内存放在空闲链表中方便我们后续使用。

标记清除算法最大的优点就是解决了引用计数算法无法回收循环引用的对象的问题 。就比如下面这段代码:

function fun() {
  const obj1 = {},
    obj2 = {},
    obj3 = {},
    obj4 = {},
    obj5 = {},
    obj6 = {}
  obj1.next = obj2

  obj2.next = obj3
  obj2.prev = obj6

  obj4.next = obj6
  obj4.prev = obj1

  obj5.next = obj4
  obj5.prev = obj6
  return obj1
}
const obj = fun()

当函数执行完毕后obj4的引用并不是0,但是使用引用计数算法并不能将其作为垃圾回收掉,而使用标记清除算法就解决了这个问题。

마크 앤 클리어 알고리즘에도 단점이 있습니다. 또한, 마크 앤 클리어 알고리즘을 사용하여 가비지 개체를 찾아도 즉시 지워질 수 없으며, 메모리 조각화 및 주소 불연속이 발생합니다. 두번째.

마킹 및 정렬 알고리즘

마킹 및 정렬 알고리즘은 마크 앤 클리어 알고리즘의 향상된 버전으로 간주할 수 있으며 해당 단계도 마킹과 클리어의 두 단계로 나뉩니다.

하지만 마크 정렬 알고리즘의 지우기 단계에서는 먼저 정렬하고 개체의 위치를 ​​이동한 다음 마지막으로 지우게 됩니다.

단계는 다음과 같습니다.

V8의 메모리 관리

V8이란 무엇입니까

V8은 이제 Node.js와 대부분의 브라우저에서 V8을 JavaScript 엔진으로 사용합니다. V8의 컴파일 기능은 실행 전이 아닌 프로그램 실행 중에(실행 중에) 컴파일을 포함하는 컴퓨터 코드를 실행하는 방법인 동적 변환 또는 런타임 컴파일이라고도 하는 Just-In-Time 컴파일을 사용합니다.

V8 엔진에는 메모리 상한이 있습니다. 64비트 운영 체제에서는 상한이 1.5G이고, 32비트 운영 체제에서는 상한이 800MB입니다. 메모리 상한이 설정되는 주된 이유는 콘텐츠 V8 엔진이 주로 브라우저용으로 준비되어 있어 큰 공간에 적합하지 않기 때문입니다. 또 다른 점은 이 크기의 가비지 수집이 매우 빠르며 사용자가 거의 느낌이 없어 사용자 경험이 향상됩니다.

V8 가비지 수집 전략

V8 엔진은 특정 규칙에 따라 메모리를 주로 두 가지 범주로 나누는 세대별 재활용 아이디어를 채택합니다. 하나는 신세대 저장 영역이고 다른 하나는 구세대 저장 영역입니다. .

새 세대의 개체는 생존 시간이 짧은 개체입니다. 간단히 말해서 새로 생성된 개체는 일반적으로 특정 용량(64비트 운영 체제의 경우 32MB, 32비트 운영 체제의 경우 16MB)만 지원합니다. 구세대의 객체 장기 생존 이벤트 또는 상주 메모리를 갖는 객체입니다. 간단히 말하면 신세대 가비지 수집 이후에도 살아남은 객체입니다.

다음 그림은 V8의 메모리를 보여줍니다.

V8 엔진은 다양한 개체에 따라 다양한 GC 알고리즘을 사용합니다. V8에서 일반적으로 사용되는 GC 알고리즘은 다음과 같습니다.

  • 세대 재활용
  • 공간 복사
  • 표시 지우기
  • 표시 정렬
  • 표시 증가

차세대 객체 가비지 수집

위에서도 소개했듯이 신세대는 객체를 짧은 생존 시간으로 저장합니다. 차세대 객체 재활용 프로세스는 복사 알고리즘과 마크 정렬 알고리즘을 사용합니다.

복사 알고리즘은 우리의 차세대 메모리 영역을 동일한 크기의 두 공간으로 나눕니다. 현재 사용되는 상태 공간을 From 상태라고 하고, 공간 상태 공간을 To 상태라고 합니다.

아래 그림과 같습니다. :

모든 활성 개체를 From 공간에 저장합니다. 공간이 가득 차면 가비지 수집이 시작됩니다.

먼저 새 세대 From 공간의 활성 개체를 표시하고 구성해야 합니다. 마킹이 완료된 후 표시된 활성 개체를 To 공간에 복사하고 마지막으로 표시되지 않은 개체를 재활용합니다. 공간. .

한 가지 더 언급해야 할 점은 객체를 복사할 때 신세대 객체가 구세대 객체로 이동된다는 것입니다.

이러한 개체에는 지정된 조건이 있습니다.

  • 가비지 수집 라운드에서 살아남은 신세대 개체는 구세대 개체로 이동됩니다.
  • To 공간 점유율이 25%를 초과하면 이 개체는 (이유의 25%는 후속 메모리 할당에 영향을 미칠까 봐 두려워서)

그래서 우리는 신세대 객체의 가비지 수집 방법이 공간을 시간으로 교환하는 것임을 알 수 있습니다.

구세대 객체의 가비지 수집

구세대 영역에 저장되는 객체는 생존 시간이 길고 넓은 공간을 차지하는 객체입니다. 복제 알고리즘을 사용할 수 없는 이유는 생존 시간이 길고 공간 점유가 크기 때문입니다. 복제 알고리즘을 사용하면 시간이 오래 걸리고 공간 낭비가 발생합니다.

구세대 개체는 일반적으로 가비지 수집을 위해 표시 지우기, 표시 정렬 및 증분 표시 알고리즘을 사용합니다.

지우기 단계에서는 마크 앤 클리어 알고리즘이 주로 재활용에 사용됩니다. 일정 시간이 지나면 너무 많은 조각이 충분한 메모리를 할당할 수 없을 때 마크 앤 클리어 알고리즘이 생성됩니다. 우주 쓰레기를 정리하는 데 사용됩니다.

구세대 개체의 가비지 수집은 증분 표시 알고리즘을 사용하여 가비지 수집 프로세스를 최적화합니다. 증분 표시 알고리즘은 아래 그림에 표시됩니다.

JavaScript는 단일 스레드이기 때문에 하나의 프로그램 실행과 가비지 수집만 동시에 실행할 수 있습니다. 이로 인해 가비지 수집이 실행될 때 프로그램이 정지되어 사용자에게 확실히 나쁜 경험을 줄 것입니다.

그래서 프로그램이 실행될 때 프로그램은 일정 시간 동안 먼저 실행된 다음 예비 표시를 수행합니다. 이 표시는 직접 도달할 수 있는 개체만 표시할 수 있으며 그 후 프로그램은 일정 기간 동안 계속 실행됩니다. 시간 및 증분 표시, 즉 간접적으로 도달할 수 있는 개체를 표시합니다. 이것을 끝까지 반복하십시오.

성능 도구

JavaScript는 메모리를 작동하는 API를 제공하지 않기 때문에 자체적으로 제공하는 메모리 관리에만 의존할 수 있지만 실제 메모리 관리가 어떤 것인지는 알 수 없습니다. 때로는 메모리 사용량을 감시해야 하는 경우가 있습니다. 성능 도구는 메모리를 모니터링하는 다양한 방법을 제공합니다.

성능 사용 단계

먼저 Chrome 브라우저를 열고(여기서는 Chrome 브라우저를 사용하고 있으며 다른 브라우저도 가능) 주소 표시줄에 대상 주소를 입력한 다음 개발자 도구를 열고 [성능] 패널을 선택합니다.

성능 패널을 선택하고 녹음 기능을 켠 다음 특정 인터페이스에 액세스하고 사용자를 모방하여 일부 작업을 수행한 다음 녹음을 중지하면 마지막으로 분석 인터페이스에서 기록된 메모리 정보를 분석할 수 있습니다.

메모리 문제 반영

메모리 문제의 주요 증상은 다음과 같습니다.

  • 페이지 로딩이 지연되거나 자주 일시 중지되며, 하단 레이어에 잦은 가비지 수집 실행이 동반됩니다. ? 잦은 가비지 수집은 메모리가 가득 차서 즉각적인 가비지 수집이 필요한 일부 코드로 인해 발생할 수 있습니다.

이 문제에 대해서는 메모리 변화 그래프를 통해 이유를 분석할 수 있습니다.

  • 페이지의 성능이 계속 좋지 않아서 우리가 사용하는 동안 페이지가 좋지 않은 느낌을 준다고 생각합니다. 하단에 메모리 확장이 있을 것입니다. 소위 메모리 확장은 특정 속도를 달성하기 위해 현재 페이지가 필요한 것보다 훨씬 더 큰 메모리를 적용한다는 것입니다. , 현재 우리는 지속적인 성능 저하 경험을 인식할 수 있습니다.

메모리 확장을 일으키는 문제는 우리 코드의 문제일 수도 있고, 기기 자체의 불량일 수도 있습니다. 이를 분석하고 찾아서 해결하려면 여러 기기에서 반복 테스트를 수행해야 합니다

  • 페이지의 성능은 시간이 지남에 따라 달라지며, 로딩 시간도 점점 길어집니다. 이 문제의 원인은 코드 메모리 누수 때문일 수 있습니다.

메모리 누수 여부를 감지하려면 Memory Total View를 통해 메모리를 모니터링할 수 있습니다. 메모리가 계속 증가하면 메모리 누수가 발생한 것일 수 있습니다.

메모리 모니터링 방법

브라우저에서 메모리를 모니터링하는 방법은 주로 다음과 같습니다.

  • 브라우저에서 제공하는 작업 관리자
  • 타임라인 순서도
  • 힙 스냅샷 분리된 DOM 검색
  • 존재 여부 확인 잦은 가비지 수집

다음으로 이러한 방법을 각각 설명하겠습니다.

작업 관리자는 메모리를 모니터링합니다

브라우저에서 [Shift] + [ESC] 키를 누르면 브라우저에서 제공하는 작업 관리자가 열립니다. 아래 그림은 Chrome 브라우저의 작업 관리자를 보여줍니다. 위 그림에서 [Nuggets] 탭의 [Memory Occupied Space]는 브라우저에서 이 페이지의 DOM이 차지하는 메모리를 나타냅니다. 계속 증가하면 새로운 DOM이 생성되고 있음을 의미합니다. 다음 [JavaScript에서 사용하는 메모리](기본적으로 활성화되어 있지 않으며 마우스 오른쪽 버튼을 클릭하여 활성화해야 함)는 JavaScript의 힙을 나타내고, 괄호 안의 크기는 JavaScript에서 도달할 수 있는 모든 개체를 나타냅니다.

타임라인은 메모리를 기록합니다

위에 설명된 브라우저에서 제공되는 작업 관리자는 페이지에 문제가 있는지 확인하는 데만 사용할 수 있지만 페이지의 문제를 찾을 수는 없습니다.

타임라인은 페이지의 상황을 밀리초 단위로 기록하는 성능 도구의 작은 탭으로, 문제를 더 쉽게 찾는 데 도움이 됩니다.

분리된 DOM을 찾기 위한 힙 스냅샷

힙 스냅샷은 현재 인터페이스 개체에 분리된 DOM이 있는지 찾는 데 매우 중점을 두고 있습니다. 분리된 DOM이 있다는 것은 메모리 누수가 있음을 의미합니다.

먼저 DOM의 여러 상태를 파악해야 합니다.

먼저 DOM 개체는 일반 DOM에 속하는 DOM 트리에 존재하며
  • 그런 다음 DOM 개체가 존재하지 않는 경우 DOM 트리에는 JS 참조가 없습니다. 이는 Garbage에 속하며 DOM 객체를 재활용해야 합니다.
  • 마지막으로 DOM 트리에는 없지만 JS 참조가 있습니다. 이것은 분리된 DOM이므로 수동으로 해제해야 합니다.
  • 분리된 DOM을 찾는 단계: 개발자 도구 열기 → [메모리 패널] → [사용자 구성] → [스냅샷 가져오기] → [필터]에
를 입력하여 아래 그림과 같이 분리된 DOM을 찾습니다.

Detached

생성된 분리된 DOM을 찾은 후 해당 DOM에 대한 참조를 찾아 릴리즈합니다.

빈번한 가비지 수집이 있는지 확인

GC작동 중 애플리케이션이 중지되기 때문입니다. 현재 가비지 수집이 자주 작동하고 시간이 너무 길면 페이지에 매우 불친절해지며 이로 인해 애플리케이션이 실행될 수 있습니다. 정지된 것처럼 보이고 사용자는 사용 중에 애플리케이션이 멈춘 것처럼 느낄 것입니다.

다음과 같은 방법으로 가비지 컬렉션이 자주 발생하는지 판단할 수 있습니다.

  • 타임라인 타이밍 차트를 사용하여 현재 성능 패널에서 메모리 추세가 자주 상승 및 하강하는지 판단하고 모니터링합니다. , 가비지 수집이 자주 발생합니다. 이때 코드를 찾아 실행 시 이러한 상황이 발생한 원인을 확인해야 합니다.
  • 브라우저 작업 관리자를 사용하기가 더 쉬워졌습니다. 작업 관리자의 주요 변경 사항은 데이터가 빈번하고 순간적으로 증가하고 감소하는 것과 빈번한 가비지 수집입니다.

【관련 추천: javascript 비디오 튜토리얼, web front-end

위 내용은 JavaScript 메모리 관리 및 GC 알고리즘에 대한 심층적인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 jb51.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제