GC(Garbage collector) - 모던자바스크립트 DeepDive

seunghw·2022년 9월 14일
2
post-thumbnail

메모리 관리의 필요성

C 언어같은 저수준 언어에서는 메모리 관리를 위해 malloc()free()를 사용합니다. 반면, 자바스크립트는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더 이상 필요하지 않을 때 자동으로 해제합니다(GC). 이러한 자동 메모리 관리는 잠재적 혼란의 원인이기도 한데, 개발자가 메모리 관리에 대해 고민할 필요가 없다는 잘못된 인상을 줄 수 있기 때문입니다.

메모리 생존주기

  1. 필요할 때 할당합니다.
  2. 할당된 메모리를 사용합니다. (읽기, 쓰기)
  3. 더 이상 필요하지 않으면 해제합니다.

1,3번

  • 저수준언어 - 명시적
  • 고수준언어 - 암묵적 작동

2번

  • 일반적으로 모든 언어에서 명시적으로 사용

GC(Garbage collector)란?

애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제 하는 기능

주방장 이야기

주방장이 조리대(메모리공간)에서 재료 및 도구들(객제,변수,함수)레시피(코드)를 따라서 요리를 하면서 이것저것 놓게 되는데 넘치지 않고 원활하게 돌아가기 위해서 조수(Garbage collector)가 더이상 사용하지 않을 것들을 판단해서 치우면 조리대에는 공간이 더 생기고 원활하게 돌아가게 됩니다.

이 조수가 바로 GC(Garbage collector)입니다.

왜?

조리대(메모리공간)가 비워줘야할 것들을 비워주지 못해서 조리대가 넘치게 되면 메모리 누수(memory leak)가 발생하기 때문에 자바를 비롯한 새로운 언어들은 GC(Garbage collector)를 도입하기 시작했다고 합니다.

메모리 누수(memory leak)

컴퓨터 프로그램 이 더 이상 필요하지 않은 메모리가 해제되지 않는 방식으로 메모리 할당을 잘못 관리 할 때 발생 하는 일종의 리소스 누수. 메모리 누수는 사용 가능한 메모리 양을 줄여 컴퓨터 성능을 저하시킵니다.

GC의 핵심개념

GC(Garbage collector) 알고리즘의 핵심 개념은 참조입니다.
A라는 메모리를 통해 (명시적이든 암시적이든) B라는 메모리에 접근할 수 있다면 "B는 A에 참조된다" 라고 합니다.

GC의 주요 알고리즘

Reference counting

어떠한 값에 대해서 어디에서도 참조(reference)하지 않고 있다면 GC는 이 값을 필요하지 않은 값으로 간주하고 이 값을 제거합니다. 한 요소가 다른요소에게 몇번 참조 되었는지 카운팅해서 그 수가 0이되면 버리기

// human 변수는 해당 object를 참조합니다.
let human = {
  name: "seunghwan"
};
//null값을 재할당한다.
human = null;

{name: "seunghwan"}이라는 값은 더이상 참조되지 않기 때문에 GC에 의해 메모리가 해제됩니다.

// human 변수는 해당 object를 참조한다 .
let human = {
  name: "seunghwan"
};
//girl에 human의 참조중인 값의 주소를 할당한다.
man = human;
//human에 null을 할당한다.
human = null;

human 더이상 {name: "seunghwan"}을 참조하고 있지 않지만, man은 참조하고 있기 때문에 해당 object는 여전히 메모리에 남아있게 됩니다.

// people 변수는 해당 object를 참조한다 .
let human = {
  name: "seunghwan"
};
//girl에 people의 참조중인 값의 주소를 할당한다.
man = human;
//people에 null을 할당한다.
human = null;
//girl에 null을 할당한다.
man = null;

만약 위의 코드처럼 human, man에 null을 할당하고 나면 {name: "seunghwan"}를 참조하고 있는 곳이 없기 때문에 해당 값은 GC에 의해 처리됩니다.

한계 : 순환참조

function f() {
  var x = {};
  var y = {};
  x.a = y;         // x는 y를 참조합니다.
  y.a = x;         // y는 x를 참조합니다.

  return "azerty";
}

f();

f()함수가 호출되고 난 이후에도 서로를 참조하고 있어서 GC가 해제하지 못하고 남아있습니다. 이러한 순한 참조는 메모리 누수의 주된 요인입니다.

mark-and-sweep

어떤 값에 대한 참조가 없는 경우는 당연히 도달이 불가능하기 때문에 메모리가 해제되어야 하는 값으로 여겨지고, 참조 되고 있다고 하더라도 root로부터 도달할수 없다고 여겨진다면 처리됩니다.

쉽게 말하자면 훑으면서 필요한 것들만 마크한 뒤에 마크 안되어 있는 부분은 버리기 즉, 루트에서 닿지 않는 변수들 버리기.

  • 도달가능성(reachablility)에 중점
  • 위의 Reference counting 알고리즘보다 효율적
  • 2012년을 기준으로 모든 최신 브라우저들은 GC에서 이 알고리즘을 사용

동작순서

  1. 가비지 컬렉터는 루트(root) 정보를 수집하고 이를 ‘mark(기억)’ 합니다. (객체가 생성될 때마다 mark bit가 0 (false)로 설정)

  2. 루트가 참조하고 있는 모든 객체를 방문하고 이것들을 ‘mark’ 합니다.(Mark 단계에서 모든 접근 가능한 객체의 mark bit가 1 (true)로 설정)

  3. mark 된 모든 객체에 방문하고 그 객체들이 참조하는 객체도 mark 합니다. 한번 방문한 객체는 전부 mark 하기 때문에 같은 객체를 다시 방문하는 일은 없습니다.

  4. 루트에서 도달 가능한 모든 객체를 방문할 때까지 위 과정을 반복합니다.

  5. mark 되지 않은 모든 객체를 메모리에서 삭제합니다.(mark bit가 0(false)으로 설정된 객체)

첫 번째 단계에선 루트를 mark 합니다.

이후 루트가 참조하고 있는 것들을 mark 합니다.

도달 가능한 모든 객체를 방문할 때까지, mark 한 객체가 참조하는 객체를 계속해서 mark 합니다.

방문할 수 없었던 객체를 메모리에서 삭제합니다.

루트에서 페인트를 들이붓는다고 상상하면 이 과정을 이해하기 쉽습니다. 루트를 시작으로 참조를 따라가면서 도달가능한 객체 모두에 페인트가 칠해진다고 생각하면 됩니다. 이때 페인트가 묻지 않은 객체는 메모리에서 삭제됩니다.

코드 예시

function f() {
  var x = {};
  var y = {};
  x.a = y;         // x는 y를 참조합니다.
  y.a = x;         // y는 x를 참조합니다.

  return "hello";
}

f();

f()함수가 호출된 후 "hello"라는 값이 return 되고 난 후에는 더이상 root에서 x,y에 도달할 수 없기 때문에 GC에 의해서 메모리가 해제됩니다.

GC의 한계

사람의 판단력을 갖춘게 아니기 때문에 100%잡아내지는 못합니다.. 그렇기때문에 개발자도 메모리 누수 방지를 꼭 신경써야 합니다. ex) 순환참조 금지 - 변수들이 서로 참조해버리면 레퍼런스 카운팅은 0이되므로 돌려막기가 되어버립니다.

느낀점

그동안 GC를 가볍게만 알고 있어서 자동이니까 다 걸러주겠지라는 안일한 생각을 깨트릴 수 있었습니다.
어떤 메모리가 여전히 필요한지 아닌지를 판단하는 것은 비결정적 문제여서 GC가 100% 모든 것들을 걸러내주진 못하기 때문에 좋은 개발을 위해서는 경각심을 갖고 메모리 관리에도 신경을 좀 더 써야겠다는 생각이 들었습니다.
또한 어떤 값이 참조된다고 해서 무조건 도달가능한 값은 아니라는 걸 알게 되었고 GC가 이런 알고리즘들의 동작방식에 대해서 좀 더 명확하게 이해할 수 있었습니다.

질문

순환참조 금지와 같은 보편적인 레퍼런스는 어떤것들이 있는지?
누수를 막기 위한방법이 언어마다 다 다르다고 하는데 어떤식으로 다른지? 어떤 디버깅, 모니터링 툴이 좋은지?
mark-and-sweep보다 더 좋은 알고리즘이 있는지? 있다면 현재 왜 쓰고있지 않은지?

참고링크

https://developer.mozilla.org/ko/docs/Web/JavaScript/Memory_Management#%EA%B0%80%EB%B9%84%EC%A7%80_%EC%BD%9C%EB%A0%89%EC%85%98
https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)#Advantages
https://ko.javascript.info/garbage-collection
https://www.youtube.com/watch?v=24f2-eJAeII
https://sustainable-dev.tistory.com/158
https://eblee-repo.tistory.com/52

profile
Lumos

0개의 댓글