>  기사  >  웹 프론트엔드  >  JS 상승의 가비지 수집 메커니즘과 일반적인 메모리 누수 문제를 해결하는 방법

JS 상승의 가비지 수집 메커니즘과 일반적인 메모리 누수 문제를 해결하는 방법

不言
不言원래의
2018-07-09 10:26:361413검색

이 글은 JS의 가비지 수집 메커니즘과 일반적인 메모리 누수 문제를 해결하는 방법을 주로 소개합니다. 이제는 필요한 친구들이 참고할 수 있도록 공유합니다.

머리말

클로저의 메모리 누수 메커니즘을 이해하고 싶었는데, "JS 고급 프로그래밍"에서 가비지 수집 메커니즘에 대한 분석을 기억했습니다. 이전에는 잘 이해하지 못했지만 1년 후에 다시 보면 이해하게 될 것입니다. , 그래서 여러분과 공유하려고 썼습니다. 마음에 드셨다면 좋아요/팔로우 및 후원을 해주시면 됩니다.


메모리 수명 주기:

  1. 필요한 메모리 할당:

문자열, 개체 등은 고정된 크기가 없으므로 js 프로그램이 문자열이나 개체를 생성할 때마다 프로그램은 해당 엔터티를 저장하기 위해 메모리를 할당하세요 .

  1. 할당된 메모리로 뭔가를 해보세요.

  2. 더 이상 필요하지 않을 때 해제 및 반환:

문자열과 개체가 더 이상 필요하지 않으면 이들이 차지하는 메모리를 해제해야 합니다. 그렇지 않으면 시스템에서 사용 가능한 모든 메모리가 소모되어 시스템이 충돌합니다. . 이것이 가비지 수집 메커니즘의 의미입니다.

소위 메모리 누수란 을 말합니다. 부주의나 오류로 인해 프로그램이 더 이상 사용하지 않는 메모리를 해제하지 못하여 메모리가 낭비되는 현상을 말합니다.


가비지 수집 메커니즘:

C, C++ 등의 언어에서는 메모리를 수동으로 관리해야 하는데, 이는 불필요한 많은 문제의 원인이기도 합니다. 다행스럽게도 js를 작성하는 과정에서 메모리 할당과 메모리 재활용이 완전히 자동으로 관리되므로 이런 걱정을 할 필요가 없습니다.

가비지 수집 메커니즘의 원리:

가비지 수집기는 고정된 시간 간격으로 더 이상 사용되지 않는 변수를 주기적으로 찾은 다음 그 변수가 차지하는 메모리를 해제합니다.

더 이상 사용되지 않는 변수는 무엇인가요?

더 이상 사용되지 않는 변수는 수명이 끝난 변수입니다. 지역 변수는 함수가 종료되고 다른 참조(클로저)가 없는 경우에만 존재합니다. 재활용 표시가 됩니다.

전역 변수의 수명 주기는 브라우저가 페이지를 언로드할 때까지 끝나지 않습니다. 즉, 전역 변수는 가비지 수집으로 처리되지 않습니다.

마크 스윕: 현재 채택된 가비지 수집 전략

작동 원리:

변수가 환경에 들어갈 때(예: 함수에서 변수 선언) 변수가 "환경에 들어갈 때"로 표시됩니다. 그런 다음 "환경 종료"로 표시합니다. "환경을 떠나다"라고 표시된 메모리는 재활용됩니다.

작업 흐름:

  1. 가비지 수집기는 작업 중에 메모리에 저장된 모든 변수를 표시합니다.

  2. 환경의 변수와 환경의 변수가 참조하는 변수의 태그를 제거하세요.

  3. 아직 태그가 있는

    변수는 삭제할 준비가 된 변수 로 간주됩니다.

  4. 마지막으로 가비지 컬렉터는 메모리 지우기의 마지막 단계를 수행하고

    표시된 값을 파괴하고 해당 값이 차지하는 메모리 공간을 회수합니다.

2008년 현재 IE, Chrome, Fireofx, Safari, Opera

모두 표시 및 청소 가비지 수집 전략을 사용하지만 가비지 수집 간격은 다릅니다.

참조 카운팅 약어: 버려진 가비지 수집 전략

순환 참조: 각 값의 참조를 추적하고 기록하는 기술

구 버전의 브라우저(예, 다시 IE)에서는 IE9 이하의 BOM 및 DOM 객체가 C++를 사용하는 COM 개체 형식입니다.

COM의 가비지 수집 메커니즘은 참조 계산 전략을 사용합니다. 이 메커니즘은 순환 참조가 발생할 때 메모리를 해제할 수 없습니다.

    var element = document.getElementById('something');
    var myObject = new Object();
    myObject.element = element; // element属性指向dom
    element.someThing = myObject; // someThing回指myObject 出现循环引用(两个对象一直互相包含 一直存在计数)。
해결책은 링크를 사용하지 않을 때 수동으로 링크를 잘라내는 것입니다.

     myObject.element = null; 
     element.someThing = null;

Elimination:

IE9는 BOM 및 DOM 개체를 실제 js 개체로 변환하여 이 가비지 수집 전략을 사용하지 않고 제거합니다. IE9 이하에서 일반적인 메모리 누수의 주요 원인입니다.

IE7에는 악명 높은 성능 문제가 있습니다. 살펴보겠습니다.

  1. 256개의 변수, 4096개의 개체(또는 배열) 리터럴 또는 64KB 문자열이 임계 값에 도달하면 가비지 수집기가 실행됩니다.

  2. js 스크립트의 수명 주기에 너무 많은 변수가 유지되면 가비지 수집기가 계속 자주 실행되어 심각한 성능 문제가 발생합니다.

IE7에서는 이 문제를 해결했습니다.


어떤 상황에서 메모리 누수가 발생할 수 있나요?

가비지 수집 메커니즘이 있지만 코드를 작성할 때 일부 상황에서는 여전히 메모리 누수가 발생할 수 있습니다. 이러한 상황을 이해하고 프로그램을 작성할 때 이러한 상황을 방지하려면 프로그램이 더욱 강력해질 것입니다.

예기치 않은 전역 변수:

우리는 위에서

전역 변수가 가비지 수집으로 처리되지 않는다고 언급했습니다 코딩에서 다음과 같은 상황이 발생할 수 있습니다.

    function foo() {
     this.bar2 = '默认绑定this指向全局' // 全局变量=> window.bar2
      bar = '全局变量'; // 没有声明变量 实际上是全局变量=>window.bar
    }
    foo();

当我们使用默认绑定,this会指向全局,this.something也会创建一个全局变量,这一点可能很多人没有注意到。

解决方法:在函数内使用严格模式or细心一点

    function foo() {
      "use strict"; 
      this.bar2 = "严格模式下this指向undefined"; 
      bar = "报错";
    }
    foo();

当然我们也可以手动释放全局变量的内存

    window.bar = undefined
    delete window.bar2

被遗忘的定时器和回调函数

不需要setInterval或者setTimeout时,定时器没有被clear,定时器的回调函数以及内部依赖的变量都不能被回收,造成内存泄漏。

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        node.innerHTML = JSON.stringify(someResource));
        // 定时器也没有清除
    }
    // node、someResource 存储了大量数据 无法回收
}, 1000);

解决方法: 在定时器完成工作的时候,手动清除定时器。

闭包:

闭包可以维持函数内局部变量,使其得不到释放,造成内存泄漏

    function bindEvent() {
      var obj = document.createElement("XXX");
      var unused = function () {
          console.log(obj,'闭包内引用obj obj不会被释放');
      };
      // obj = null;
    }

解决方法:手动解除引用,obj = null

循环引用问题

就是IE9以下的循环引用问题,上文讲过了。

没有清理DOM元素引用:

    var refA = document.getElementById('refA');
    document.body.removeChild(refA); // dom删除了
    console.log(refA, "refA");  // 但是还存在引用 能console出整个p 没有被回收

不信的话,可以看下这个dom。

解决办法:refA = null;

console保存大量数据在内存中。

过多的console,比如定时器的console会导致浏览器卡死。

解决:合理利用console,线上项目尽量少的使用console,当然如果你要发招聘除外。


如何避免内存泄漏:

记住一个原则:不用的东西,及时归还,毕竟你是'借的'嘛

  1. 减少不必要的全局变量,使用严格模式避免意外创建全局变量。

  2. 在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。

  3. 组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。

关于内存泄漏:

  1. 即使是1byte的内存,也叫内存泄漏,并不一定是导致浏览器崩溃、卡顿才能叫做内存泄漏。

  2. 一般是堆区内存泄漏,栈区不会泄漏。

基本类型的值存在内存中,被保存在栈内存中,引用类型的值是对象,保存在堆内存中。所以对象、数组之类的,才会发生内存泄漏

  1. 使用chorme监控内存泄漏,可以看一下这篇文章


结语

了解了内存泄漏的原因以及出现的情况,那么我们在编码过程中只要多加注意,就不会发生非常严重的内存泄漏问题。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

原生JS基于window.scrollTo()封装垂直滚动动画工具函数

JavaScript创建对象的四种方式

利用javascript判断浏览器类型

위 내용은 JS 상승의 가비지 수집 메커니즘과 일반적인 메모리 누수 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.