[JavaScript] 메모리 관리

전홍석·2025년 9월 30일

javascript

목록 보기
11/11
post-thumbnail

C 언어 같은 저수준 언어에서는 메모리 관리를 위해 malloc(), free() 를 사용하지만 JS는 객체가 생성되었을 때 자동으로 메모리를 할당하고 더 이상 필요하지 않을 때 자동으로 해제한다

메모리 생명주기

  1. 필요할 때 할당
  2. 할당된 메모리를 사용
  3. 더 이상 필요하지 않으면 해체

JavaScript 메모리 할당

  • 리터럴 : const n =123, const s = "abc", const o = { a : 1} 선언만으로 메모리 할당
  • 함수 호출 및 생성자 : new Date(), Document.createElement('div')
  • 메서드나 API가 새로운 객체를 만들어 반환 : array.concat(), str.substr()

값 사용

값 사용이란 기본적으로 할당된 메모리를 읽고 쓰는 것으로, 변수나 객체 속성의 값을 읽고 쓰거나 함수 호출 시 함수에 인수를 전달하여 수행할 수 있다.

할당된 메모리 더 이상 필요없을 때 해제

할당된 메모리가 더 이상 필요없을 때를 알아내기가 가장 어렵기 때문에 해당부분에서 대부분의 메모리 관리 문제가 발생한다.

저수준 언어에서는 개발자가 직접 메모리가 필요없어질 때를 결정하고 해제하는 방식을 사용하지만, JS와 같은 고수준 언어들은 GC(가비지 콜렉션) 이라는 자동 메모리 관리 방법을 사용한다.

가비지 콜렉션

프로그램이 더 이상 필요로 하지 않는(도달 불가능한) 메모리(객체)를 자동으로 찾아서 회수하는 시스템
수동으로 해제하지 않아도 되게 해주지만, 언제/어떻게 수거되는지 이해하지 못하면 메모리 누수나 성능 문제를 만들 수 있다.

참조-세기(Reference-counting) 가비지 콜렉션

!! 참고 : 최신 브라우저는 더 이상 해당 방식을 사용하지 않음

참조-세기(Reference-counting) 가비지 콜렉션은 어떤 다른 객체도 참조하지 않는 객체를 더 이상 필요 없는 객체로 여기고 수집한다.

let x ={
	a: {
    	b: 2
    }
}

// 메모리에 객체가 생성된다
// obj1 = { a: obj2 }  obj2 = { b: 2 }
// 변수 x 는 obj1를 참조
// x -> obj1
// 		a -> obj2

let y =x	// y 변수는 obj1를 참조하는 두번째 변수
			// x -> obj1 <- y
			// 		a -> obj2
            
x=1			// y 변수가 obj1를 참조하는 유일한 변수
			// x -> 1
            // obj1 <- y
			// 		a -> obj2

let z = y.a 	// z 변수는 obj2를 참조하는 두번째 변수
                // x -> 1
                // obj1 <- y
                // 		a -> obj2 <- z

y = "javascript"  	// x -> 1
                	// "javascript" <- y
                	// 	obj2 <- z
					// 	해당 단계에서 obj1은 GC 대상
z = null

// x -> 1
// "javascript" <- y
// 	null <- z

도달 가능성(Reachability)
JS에서 객체가 GC 대상이 되는 조건으로 더이상 root(전역 변수, 스택 변수 등)에서 도달할 수 없는 객체는 참조가 내부에 있어도 외부에서 접근할 수 없으면 GC는 해당 객체를 수거할 수 있다
따라서, y = "javascript" 단계에서 obj1을 참조하는 변수가 없어짐에 따라 도달가능 하지 않은 객체가 되어 GC 대상이 된다.

function f() {
	const x = {}
    const y = {}
    x.a = y
    y.a = x
}
f()

위에 같이 순환 참조를 다루는 일에는 한계가 있다.
함수 호출이 완료되면 두 객체는 스코프를 벗어나게 되어 할달된 메모리가 회수되어야 하지만 두 객체가 참조하고 있으므로 GC 대상이 되지 않는다.

Mark-and-Sweep 알고리즘

현재 모든 최신 엔진이 사용하는 GC 알고리즘으로, roots 라는 객체의 집합을 갖는데 주기적으로 GC는 roots 부터 시작해 roots가 참조하는 객체들, roots가 참조하는 객체가 참조하는 객체 등을 찾는다.
roots 로 부터 시작하여 GC는 모든 도달 가능 객체들을 찾고, 도달할 수 없는 모든 객체들을 수집한다.

즉, GC는 root 부터 시작해서 모든 도달 가능한 객체에 mark를 하고 mark가 없는 객체는 sweep 된다.

profile
취뽀까지 숨참기

0개의 댓글