[컴퓨터공학] 기초 | 가비지 컬렉션(Garbage collection)

Eunji Lee·2023년 1월 27일
0

[TIL] 컴퓨터공학

목록 보기
3/3
post-thumbnail

개요

의미

프로그램에서 더 이상 사용하지 않는 메모리를 자동으로 정리하는 것

특징

  • 운영체제로부터 할당받은 메모리를 관리하는 역할
    • 메모리 할당을 추적하고, 할당된 메모리 블록이 더이상 필요하지 않게 되었는지를 “스스로” 판단하여 필요하지 않다고 판단이 된다면 해당 메모리를 해제
  • 프로그램 언어마다 가비지 컬렉션이 없을 수도 있음
    • 고수준 언어: 가비지 컬렉션이 보통 있음
      • ex. 자바, C#, 자바스크립트 등
    • 저수준 언어: 가비지 컬렉션이 없음
      • 메모리 관리를 위해 malloc()free()를 사용해 개발자가 스스로 메모리를 할당하고 해제해야함
        • ex. C

(참고) 고수준 언어와 저수준 언어

고수준 언어저수준 언어
인간 친화적인 언어기계 친화적인 언어
컴파일러 또는 인터프리터를 사용하여 컴퓨터가 읽을 수 있는 기계어 코드로 변환해야 하며, 하드웨어와 직접 상호 작용하지는 않음컴파일러나 인터프리터가 필요하지 않으므로 고수준 언어보다 빠른 편
인간이 이해하기 쉽고 다양한 작업을 수행하는 프로그램을 개발레지스터 및 메모리와 직접 상호 작용을 할 수 있기 때문에 전반적으로 빠르게 실행되는 응용 프로그램을 빌드하는 데에 사용



메모리 생존 주기


(출처: 🧠 Memory leaks and Garbage Collection 🗑️ in JavaScript.)

메모리 할당(Memory Allocation)

개발자를 대신해서 JavaScript는 값이 선언될 때 자동으로 메모리를 할당함

할당된 메모리 사용(Memory Usage)

  • 기본적으로 할당된 메모리를 읽고 쓰는 것을 의미
  • 변수나 객체 속성의 값을 읽고 쓰거나, 함수 호출 시에 함수에 인수를 전달하여 수행하는 방식으로 발생

메모리 해제(Memory Release)

더이상 필요하지 않은 해제함




가비지 컬렉션의 알고리즘

선행 개념

  • 참고(reference)
    • 명시적이든, 암묵적이든 관계없이 메모리 관리 관점에서 어떤 객체가 다른 객체에 접근할 수 있다면 다른 객체를 참조한다고 말함
    • 예를 들어서, JavaScript 객체는 자신의 프로토타입(prototype)에 대해 암묵적인 참조를 갖고 있고, 자신의 속성(property) 값에 대한 명시적 참조도 가지고 있음
  • 객체를 참조한다는 의미
    • 좁은 의미: 일반적인 JavaScript 객체를 참조함
    • 넓은 의미: 일반적인 JavaScript 객체 뿐만 아니라 함수 스코프(function scope)나 글로벌 렉시컬 스코프(global lexical scope)까지도 포함

렉시컬 스코핑(lexical scoping)
변수 이름이 중첩된 함수에서 해석되는 방식을 정의하는 것으로, 중첩되어 있는 더 안쪽의 함수는 부모 함수가 값을 반환한 다음에도 부모 함수의 스코프를 포함하고 있음

레퍼런스 카운팅(참조 횟수 계산)

  • 한 객체를 참조하는 변수의 수를 추적하는 방법으로 가장 단순한 형태의 가비지 컬렉션 알고리즘
  • 객체를 참조하는 변수는 처음에는 특정 메모리에 대해 레퍼런스가 하나뿐이지만, 변수의 레퍼런스가 복사될 때마다 레퍼런스 카운트가 늘어남
  • 객체를 참조하고 있던 변수의 값이 바뀌거나, 변수 스코프를 벗어나면 레퍼런스 카운트는 줄어듦
  • 레퍼런스 카운트가 0이 되면, 그 객체와 관련한 메모리는 비울 수 있음
    • 레퍼런스 카운트가 0이 된다는 말은 아무도 그 객체에 대한 레퍼런스를 가지고 있지 않다는 말과 동일함
  • 순환 참조로 인한 문제가 생길 가능성이 높음

예시

function reference() {
  var obj1 = {};
  var obj2 = {};
  obj1.p = obj2;
  obj2.p = obj1;
}
reference();
  • 위 코드에서는 두 객체가 생성되고 서로를 참조하고 있는 형태이기 때문에 순환 참조가 발생
  • 이 객체들은 함수 호출 뒤에는 스코프를 벗어나게 되므로 실질적으로 쓸모없음
  • 이들이 차지하던 메모리는 반환될 수 있지만, 레퍼런스 카운팅 알고리즘에서는 두 객체가 적어도 한 번은 참조한 것으로 간주되기 때문에 둘 다 가비지컬렉션이 될 수 없음

트레이싱

  • 한 객체에 flag를 두고, 가비지 컬렉션 사이클마다 flag에 표시 후 삭제하는 mark and sweep 방법
  • 객체에 in-use flag를 두고, 사이클마다 메모리 관리자가 모든 객체를 추적해서 사용 중인지 아닌지를 표시(mark)
  • 그 후 표시되지 않은 객체를 삭제(sweep)하는 단계를 통해 메모리를 해제
  • 현재 대부분의 가비지 컬렉션이 mark and sweep 알고리즘을 이용한 가비지 컬렉터를 장착
  • 기준: 해당 객체에 닿을 수 있는지 (reachable)
    • 레퍼런스 카운팅 방법보다는 나은 방법이라고 할 수 있음
    • ‘참조받지 않는 객체’는 ‘닿을 수 없는 객체’기 때문에 가비지 컬렉션을 통해 메모리를 해제할 수 있기 때문

실행 방식

  1. 가비지컬렉터가 모든 루트의 완전한 목록을 만듦

루트(Roots)

  • 일반적으로 루트는 코드에서 참조되는 전역 변수를 의미함
  • ex. 자바스크립트에서 루트로 동작할 수 있는 전역 변수는 window 객체이며, Node.js에서 이와 동일한 객체는 global
  1. 모든 루트와 그 자식들을 검사해서 활성화 여부를 표시하고, 루트가 닿을 수 없는 것들은 가비지로 표시됨

  2. 가비지컬렉터가 활성으로 표시되지 않은 모든 메모리를 OS에 반환




메모리 누수

  • 예상치 못한 참조로 인해 주로 발생
  • 예상치 못한 참조는 개발자는 더 이상 사용되지 않을 것이라 생각했지만, 어떠한 이유로 활성화 상태인 루트 트리 안에 존재하는 메모리 조각들
  • 자바스크립트에서 예상치 못한 참조는 더이상 사용되지 않지만 코드 상 어딘가에 유지되어 해제되지 못한 변수들
  • 형태
    • 우발적으로 생성된 전역변수
    • DOM 외부에서의 참조
    • 클로저의 잘못된 사용

0개의 댓글