자바스크립트 가비지 컬렉션 (JavaScript Garbage Collection)

이기곤·2022년 4월 19일
0

항해99 면접준비

목록 보기
1/1

Garbage Collection

JavaScript는 더 이상 사용되지 않을 변수와 함수를 Heap(메모리 힙)에서 제거함으로써 메모리를 효율적으로 관리한다. 이러한 역할을 수행해주는 도구를 Garbage Collector라고 한다.

  • javaScript, Python, Java 는 가비지 컬렉터가 자동으로 메모리를 관리 해준다.
  • C, C++ 등 수동으로 메모리 관리하는 언어는 기본적으로 가비지 컬렉터가 없지만, 구현하여 사용할 수 있다.

메모리 생명 주기

  • 할당(allocate): 프로그램이 사용할 수 있도록 운영체제가 메모리를 할당하는 것. JavaScript와 같이 고수준 언어에서는 개발자가 신경쓸 일이 없지만, 저수준 언어에서는 개발자가 명시적으로 처리해야한다.
  • 사용(use): 코드 상에서 할당된 변수를 사용함으로써 읽기 및 쓰기 작업이 이루어진다.
  • 해제(release): 프로그램에서 필요하지 않은 메모리를 OS에 되돌려주는 단계이다. 할당과 마찬가지로 저수준 언어에서는 이를 명시적으로 처리해야 한다.

Garbage Collection 기준

JavaScript는 도달 가능성(reachability) 이라는 개념을 사용해 메모리 관리를 수행한다.
‘도달 가능한(reachable)’ 값은 쉽게 말해 어떻게든 접근하거나 사용할 수 있는 값을 의미하며, 도달 가능한 값은 메모리에서 삭제되지 않는다.

예시로 아래 값들은 무조건 적으로 도달 가능한 값들이기에, 명백한 이유 없이는 삭제되지 않는다.

  • 현재 함수의 지역변수와 매개변수
  • 중첩 함수의 체인에 있는 함수에서 사용되는 변수와 매개변수
  • 전역 변수
  • 기타 등등...

Garbage Collection 장단점

장점

  • 메모리 관리를 해줌으로써 사용자는 완벽하게 할 필요가 없어진다.

단점

  • 언제 가비지 컬렉션이 진행될지 예측하기 어렵다.
    객체가 쓸모 없어지는 시점에 정확히 메모리가 해제되지 않기 때문에 최적의 메모리 관리가 되지 않는다.
  • 가비지 컬렉터가 동작하는 시간이 든다.
    어떤 객체가 쓸모 없는지 판단하는 시간이 소요된다.

Garbage Collection 알고리즘

마크 앤 스위프 (Mark and Sweep Algorithms) 알고리즘
가비지 컬렉션 알고리즘이 의존하고 있는 주요 개념은 참조(reference)다. 만약 그것을 가리키는 참조가 하나도 없는 경우(Reachable 하지 않은 경우) 가비지컬렉션 대상(Garbage collectible)이 된다.

자바스크립트는 마크 앤 스위프 알고리즘을 사용하며, 이는 다음의 세 단계를 거친다.

  1. 가비지 컬렉터는 모든 루트로부터 완전한 목록을 만들어낸다.(루트는 전역 객체, 즉 window 객체 혹은 root 객체를 의미한다.)
  2. 그런 다음 모든 루트와 그 자식들을 검사해서 활성화 여부를 표시(Mark)한다.
  3. 활성으로 표시되지 않은 모든 메모리를 쓸어담아(Sweep) OS에 반환한다.
    이 과정의 단점도 있긴 하다.
  • 어떤 메모리를 해제할지 결정하는 데 비용이 든다. 특히, 개발자가 이미 인지하고 있는 경우에도 가비지 컬렉터가 작동하므로 작업이 오버헤드가 될 수 있다.
  • 특히, 표시(Mark) 단계에서 메모리 내용이 변경되지 않아야 하기 때문에 전체 시스템의 실행이 정지된다.이 과정에서 프로그램 퍼포먼스가 저하될 수 있다.

    참고!!

    • 레퍼런스 카운팅 알고리즘(Reference Counting Algorithms)
      참조 횟수를 계산 하는 알고리즘으로, 이 알고리즘의 한계는 순환참조의 경우 두 객체가 적어도 한 번은 참조한 것으로 간주해서 가비지컬렉션이 될 수 없다. 이 한계를 보완한 알고리즘이 마크 앤 스위프 알고리즘 이다.

메모리 누수

메모리 힙이 제대로 관리되지 않을 경우, 현재는 필요가 없음에도 불구하고 메모리 공간에서 제거되지 않은 상태로 유지되는 경우를 의미한다. 사실, 그동안은 웹개발자에게 메모리 누수는 그렇게 걱정할 부분이 아니었다고 한다. 페이지 안의 링크를 클릭하게 되면, 결국 메모리상에 새 페이지를 불러오기 때문이다. 하지만 오늘날 Single Page Application이 보편화되면서 오랜 시간 동일한 페이지에서 사용이 이루어지게 되었고, 메모리 누수 방지의 필요성이 증가했다.

JavaScript에서 메모리 누수를 발생시키는 대표적인 4가지 사례

  1. 전역 변수(Global variables)를 많이 선언한 경우
    선언되지 않은 변수를 참조하면 이는 자동적으로 전역 변수로 생성된다. 엄격모드(Strict mode)를 사용하면 전역변수의 사용을 미리 예방 할 수 있다.
    명시적으로 사용된 전역변수는 회수되지 않는다. 전역변수를 사용해야 한다면, 사용된 후에는 반드시 null처리 해주는 것이 좋다.
  2. 타이머 혹은 이벤트리스너를 클린업(Clean up)하지 않은 경우
    setInterval의 경우 클린업해주지 않으면 계속 사용 중인 것으로 간주되어 가비지 컬렉터에 의해서 제거되지 못하고 메모리 공간을 계속 차지하게 된다.
    이벤트 리스너의 경우도 removeEventListener를 해주지 않으면 DOM요소의 수명보다 오래 남게 되어 메모리 누수가 발생한다.
  3. 클로저
    외부 함수의 실행이 끝난뒤에도 사라지지 않고 상위 렉시컬 환경을 기억하는 것을 클로저라고 하는데, 이 기억을 위해 메모리가 필요하고 이 메모리는 참조를 제거하지 않는 한 GC에 의해 회수되지 않는다.
  4. DOM을 벗어난 참조
    DOM에서는 지워졌지만 자바스크립트에 의해 여전히 메모리를 차지하고 있는 경우를 말한다. DOM요소가 코드 내에서 변수나 객체에 의해 참조되고 있으면 DOM 내에서 삭제되어도 GC에 의해 회수되지 않는다.

참고자료

https://tillog.netlify.app/posts/garbage-collection
https://eblee-repo.tistory.com/52
https://velog.io/@bumsu0211/JavaScript-Garbage-Collection#garbage-collection

profile
개발자로 성장중......

0개의 댓글