Algorithm|Javascript Algorithm

자바스크립트 메모리 생존 주기 (1)

0

크리스는 C언어를 배우는 친구가 "나 어제 malloc하고 free 안 해서 메모리 터졌어"라고 투덜대는 걸 들었다.

크리스는 속으로 웃었다.

"ㅋㅋ 원시인인가? 자바스크립트는 그런 거 신경 안 써도 알아서 다 해주는데."

하지만 며칠 뒤, 크리스가 만든 웹 페이지를 켜놓고 점심을 먹고 왔더니 크롬 탭이 **"앗, 이런! (Aw, Snap!)"**이라며 죽어 있었다.

메모리 사용량이 4GB를 넘겨서 강제 종료된 것이다.

"알아서 다 해준다며! 왜 터지는 건데?"

자바스크립트가 메모리를 자동으로 관리해 주는 것은 맞다. 하지만 "어떻게" 관리하는지 모르면, 밑 빠진 독처럼 메모리가 새어나가는 코드를 짜게 된다.

이제 알고리즘을 넘어, 코드가 살아 숨 쉬는 공간인 **메모리(Memory)**의 세계로 들어가 보자.

1. 메모리의 삶: 태어나서, 일하고, 죽는다

프로그래밍 언어가 무엇이든, 메모리의 생존 주기(Life Cycle)는 딱 3단계로 나뉜다.

  • 할당 (Allocation): 필요한 만큼 메모리 공간을 확보한다. ("호텔 체크인")
  • 사용 (Use): 할당된 공간에 값을 쓰거나 읽는다. ("투숙")
  • 해제 (Release): 다 썼으면 공간을 비워주고 반납한다. ("체크아웃")
  • C나 C++ 같은 저수준 언어는 개발자가 이 3단계를 모두 직접 명령해야 한다. (malloc -> read/write -> free)

    반면, 자바스크립트는 1번과 3번을 자동으로 처리한다. 바로 여기서 오해가 시작된다. **"자동이니까 신경 꺼도 되겠지?"**라는 착각이다.

    2. 1단계: 할당 (Allocation)

    자바스크립트는 우리가 변수를 선언할 때, 데이터 타입에 맞춰 알아서 메모리를 빌려온다.

    JavaScript

    var n = 123; // 숫자를 위한 메모리 할당 var s = "azerty"; // 문자열을 위한 메모리 할당 var o = { a: 1, b: null }; // 객체와 그 안의 값들을 위한 메모리 할당

    여기서 중요한 점은 데이터가 어디에 저장되느냐다.

    메모리 공간은 크게 **스택(Stack)**과 힙(Heap) 두 구역으로 나뉜다.

    스택 (Stack): 정적 메모리 할당

  • 누가 사나?: 숫자, 불리언(true/false) 같은 원시 타입(Primitive) 데이터.
  • 특징: 크기가 정해져 있어서 착착 쌓아 올린다. 속도가 매우 빠르다.
  • 힙 (Heap): 동적 메모리 할당

  • 누가 사나?: 객체(Object), 배열(Array), 함수(Function) 같은 참조 타입(Reference) 데이터.
  • 특징: 크기가 얼마나 커질지 모른다. 빈 공간을 찾아서 널찍하게 잡아야 하므로 스택보다 좀 느리고 복잡하다.
  • 3. 2단계: 사용 (Use)

    할당된 변수를 읽거나 수정하는 단계다.

    JavaScript

    console.log(n); // 읽기 n = 456; // 쓰기 (재할당)

    우리가 코딩하면서 하는 대부분의 작업이 여기에 해당한다. 여기까지는 문제 될 게 없다.

    4. 3단계: 해제 (Release) - 문제의 시작

    가장 어렵고 중요한 단계다.

    "더 이상 필요 없는 메모리"를 찾아서 되돌려줘야 한다. 그렇지 않으면 브라우저가 쓸 수 있는 메모리가 점점 줄어들다가 결국 뻗어버린다. 이를 **메모리 누수(Memory Leak)**라고 한다.

    저수준 언어에서는 개발자가 "이제 obj는 필요 없어, free(obj)!"라고 명시하지만, 자바스크립트는 엔진 내의 **가비지 콜렉터(Garbage Collector, GC)**라는 청소부가 대신해준다.

    하지만 이 청소부에게는 치명적인 한계가 있다.

    "이 데이터가 앞으로 정말로 필요 없을지, 기계가 완벽하게 판단하는 것은 불가능하다."

    JavaScript

    let data = { value: "엄청 큰 데이터" }; // ... 코드가 길어짐 ... // 개발자: "난 이제 data 안 쓸 건데?" // GC: "어? 근데 저기 다른 함수에서 data를 참조하고 있는데? 아직 필요한가 본데?" (청소 안 함)

    이런 오해(참조)가 쌓이고 쌓이면 GC는 쓰레기를 끌어안고 살게 되고, 결국 메모리가 터진다.

    개발자가 GC의 작동 원리를 알아야 하는 이유가 바로 이것이다. 청소부가 헷갈리지 않게 힌트를 줘야 하기 때문이다.

    5. 결론: "자동"은 "만능"이 아니다

  • 할당: 변수 선언 시 자동으로 일어난다. (스택 vs 힙)
  • 사용: 값을 읽고 쓴다.
  • 해제: 가비지 콜렉터(GC)가 알아서 해주지만, 우리가 코드를 잘못 짜면 GC가 청소를 못 한다.
  • 그렇다면 GC는 도대체 어떤 기준으로 "이건 쓰레기야!"라고 판단할까?

    그리고 크리스의 코드는 왜 GC를 혼란스럽게 만들었을까?

    다음 글, "[JavaScript] 가비지 콜렉션(Garbage Collection): 쓰레기 청소부의 기준" 편에서 계속된다.


    🔗 참고 링크

  • MDN - Memory Management
  • V8 Memory Management
  • Comments (0)

    0/1000 characters
    Loading comments...