티스토리 뷰

개요

이전 스터디를 듣다가 왠지 자바와 자바스크립트의 메모리가 비슷한 것 같다는 생각이 들었고, 왜 힙 영역에 변수를 저장하는지가 궁금해짐.

참고한 블로그 정리하는 내용.

 

내용

대부분의 메모리 생명 주기는 비슷하다.

  • 메모리 할당
    • OS가 생성한 객체에 필요한 메모리를 자동으로 할당한다.
    • 객체는 메모리 관리의 맥락에서 Object 뿐만 아니라 함수와 함수의 스코프까지 포함하는 개념이다.
    • 저수준 언어의 개발자는 명시적 처리가 필요하다.
    • 고수준 언어는 개발자가 신경 쓸 필요가 없는 부분이다.
  • 메모리 사용
    • 할당된 메모리를 프로그램이 사용하는 단계.
    • 개발자가 코드에서 명시적으로 수행하여 이루워지는 작업.
    • 메모리를 읽고 쓰는 작업은 곧 변수에서 읽거나 변수에 쓰는 작업을 의미함.
    • 함수에 인수를 넘겨줄 때도 일어남.
  • 메모리 해제
    • 프로그램에서 더 이상 필요하지 않는 메모리 전체를 반환하여 재사용 가능하게 해주는 단계.
    • 이 단계는 JS 엔진에서도 처리되며 GC가 사용되는 영역이다.
    • 이 부분 역시 저수준 언어의 개발자는 명시적 처리가 필요하다.

 

메모리의 힙과 스택

  • Code Area
    • 실행할 js 코드를 저장함.
  • 스택 (정적 메모리 할당)
    • 원시값 (String, number, bigint, boolean, undefined, symbole, null), 참조 reference (객체, 함수) 할당
    • 크기가 변경되지 않을 것임을 알고있기에,  엔진에서 각 값에 대한 고정된 크기의 메모리를 사전에 할당.
    • 실행 직전에 메모리를 할당 하기에 정적 메모리 할당이라 부름.
    • 값과 전체 스택에 대한 제한은 브라우저에 따라 다르게 구현됨.
    • 컴파일 타임에 크기를 알 수 있음.
  • 힙 ( 동적 메모리 할당)
    • 객체 및 함수 할당
    • 엔진은 고정된 크기의 메모리를 할당하지 않는다.
    • 필요에 따라 더 많은 공간을 할당함. (객체당 제한이 없음)
    • 런타임에 크기를 알 수 있음.

 

자바스크립트의 참조

  • 자바스크립트에서 변수를 선언하고 값 할당하면 메모리 어딘가에 위치하게 되는데 이 영역을 immutable, mutable 영역이라 부름.
  • 모든 변수는 먼저 스택을 가르키고, 원시값이 아닌 경우 스택에서는 힙의 객체에 대한 참조가 포함됨.
  • 힙의 메모리는 특정한 방식으로 정렬되지 않기에 스택에 대한 참조를 유지해야함.
  • 자바스크립트의 객체와 함수는 힙에 저장되고, 원시값과 참조는 스택에 저장됨.

 

가비지 컬렉션

  • 힙 내부에는 세 개 이상의 가비지 컬렉션이 존재하고, 각각 다른 내부 알고리즘을 통해 메모리를 최적화 시킨다.
  • 가비지 컬렉션에는 GC Root가 존재하는데 이 것은 힙 외부에서 접근할 수 있는 변수나 오브젝트를 뜻한다.
  • 어떤 변수나 함수가 더 이상 필요하지 않다는 것을 인식하게 되면, 가비지 컬렉션이 해당 변수 및 함수의 메모리를 해제함.
  • 메모리의 필요 여부에 대한 결정을 하기 위해 Reference-counting garbage collection과 Mark-and-Sweep 알고리즘을 사용.

 


Reference-counting 

  • 어느 한 메모리가 다른 메모리를 얼마나 많이 참조하는지 횟수를 세어 메모리에 접근 가능과 불가능을 나누는 방식.
  • 객체, 메모리 블록, 디스크 공간 등을 참조하는 Reference, Pointer, Handle의 갯수를 저장하는 기술.
  • 해당 알고리즘은 순환 참조를 고려하지 않음. 
  • 하나 이상의 객체가 서로 참조하지만, 더 이상 코드를 통해 접근할 수 없을 때 문제가 발생함.
  • 참조횟수를 추가하는것보다 빼는 부분에 있어서 정수 감소, 조건문, 함수 호출 등이 실행될 수 있기 때문에 오버헤드 단점이 존재한다.

Mark-and-Sweep

 

  • 주어진 객체에 대한 참조를 계산하는 대신, 루트 객체에서 도달할 수 있는지 감지.
  • 여기서 루트란 브라우저에서는 Window객체, Node.js에서는 global 객체를 가르킴.
  • 루트에서 도달할 수 없는 객체는 mark (쓰레기)로 표시 후 나중에 sweep(청소) 함. (루트 객체는 제외됨)
  • 2012년부터 모든 최신 브라우저에서 구현되었음.

트레이드 오프

  • 메모리 사용량
    • 정확히 언제 메모리가 더 이상 필요하지 않은 것인지 알 수 없음.
    • 할당된 메모리를 수집할 시기 및 여부는 결국 가비지 컬렉션에게 달려있음.
    • 메모리가 가능한 효율적이어야 한다면 로우레벨의 언어를 사용하는것이 좋음.
      • 성능
        • mark 수집 알고리즘은 sweep를 위해 주기적으로 실행됨.
        • 언제 일어날지 개발자가 모르기 때문에 빈번하게 mark 수집을 할 경우 성능 영향 미칠 수 있음.
        • 다만 사용자나 개발자에겐 미미한 정도의 영향
  • 메모리 누수
    • 전역변수에 데이터를 저장하는 것은 일반적인 유형의 메모리 누수이다.
      • const나 let 키워드 대신 var를 사용하거나 생략한다면 엔진이 window 객체에 변수를 할당함.
      • function 키워드로 정의한 함수도 마찬가지임.
      • 전역 변수를 사용할 수 있지만 메모리를 해제한다면 변수에 null을 할당해야한다. 
        • 예 : window.users = null;
  • 잊어버린 타이머와 콜백 
    • 타이머
      • 단일 페이지 어플리케이션에서 이벤트 리스너와 콜백을 동적으로 추가할 때 주의해야함.
      • 다른 페이지로 이동할 때도 여전히 백그라운드에서 실행되기 때문에 필요하지 않은 타이머는 취소해야한다.
        • 예 : cleraInterval(intervalId);
    • 콜백
      • 구식 브라우저에서는 리스너 수집할 수 없었지만 요즘에는 문제가 되지 않는다.
      • 문제되지 않더라도 더 이상 사용하지 않는 이벤트 리스너는 제거하는 것이 좋다.
  • DOM 참조
    • DOM 엘리먼트를 저장할 때 발생한다.
    • DOM 엘리먼트가 가바지 컬렉터에서 수집되려면 엘리먼트를 제거할 때, 배열에서도 제거해야한다.
    • 모든 DOM 엘리먼트는 부모 노드에 대한 참조도 유지하기 때문에 가비지 컬렉터가 부모와 자식을 수집하는 것을 방지함.

 

참고

1. https://felixgerschau.com/javascript-memory-management/

 

JavaScript's Memory Management Explained | Felix Gerschau

Even though the JavaScript engine manages memory for us, it's good to know what happens under the hood.

felixgerschau.com

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함