ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • V8 Memory Structure
    카테고리 없음 2023. 2. 22. 22:36

    Contents

    • V8 Memory Structure 개요
    • Heap
    • Stack
    • V8 메모리 사용(Stack, Heap)
    • V8 메모리 관리: Garbage Collection(GC)
      • Minor GC
      • Major GC

    V8 Memory Structure Overview

    JavaScript는 단일 스레드이기 때문에 V8은 새로운 작업을 수행할 때마다 새 프로세스를 생성 및 실행한다.

    실행중인 프로그램은 V8 프로세스에서 할당된 일정량의 메모리로 표현되고, 이를 Resident set이라 한다.

     

    Heap

    V8의 object 혹은 동적 데이터를 저장하는 곳으로 Resident set의 가장 큰 부분을 차지하고, GC(Garbage Collection)이 일어나는 곳이기도 하다.

    전체 공간에서 가비지가 수집되지는 않고, Young, Old Space에서만 수집되어 관리된다.

    • New Space(Young generation)

    Heap - New Space(Young generation)

    • 새로운 객체가 할당되며 대부분의 수명이 짧음
    • Scavenger(Minor GC)에 의해 관리됨
    • min_semi_space_size(initial, 초기값) 및 max_semi_space_size(max, 최대값) V8 플래그를 사용하여 제어가 가능
    • Old Space(Old generation)

    Heap - Old space(Old generation)

    • Minor GC이 두번 발생할 동안 New Space에서 살아 남은 객체들이 이동하는 영역
    • Mark-Sweep or Mark-Compact(Major GC)에 의해 관리됨
    • Initial_old_space_size(initial, 초기값) 및 max_old_space_size(max, 최대값) V8 플래그를 사용하여 제어 가능
      • Old pointer space : Minor GC에 의해 제거되지 않고 살아 남은 객체 들이며 이 객체들은 다른 객체를 참조함
      • Old data space : Old pointer space의 객체가 가리키는 데이터가 저장된 곳으로, 다른 객체를 참조하지 않음
    • Large object space다른 영역의 제한된 크기보다는 더 큰 객체들이 할당됨

    Heap - Large object space

    • 각 객체는 자체 mmap 메모리 영역을 갖음
    • Large object 들은 GC로 이동하지 않음
    • Code space(JIT, Just-In-Time)

    Heap - Code space

    • 컴파일러가 컴파일된 코드들을 저장하는 곳
    • 유일하게 실행 가능한 메모리가 있음(코드들은 "Large object space"에 할당될 수도 있고, 실행도 가능함)
    • Cell, Property cell, Map space

    Heap - Cell, Property cell, Map space

     

    • 각 영역은 모두 같은 크기의 객체들을 저장하고, 어떤 종류의 객체 참조할지에 대한 제약이 있어서 저장 단순하게 만듬
    각 영역은 페이지들로 구성되어있다.
    페이지는 운영체제에서 mmap 또는 Windows에서 mapViewOfFile로 할당된 연속된 메모리 청크를 의미한다.

     

    각 페이지의 크기는 Large object space를 제외하고 1MB를 갖는다.

     

    Stack

    V8 프로세스 하나당 하나의 Stack을 갖는다.

    메서드, 함수 프레임, 원시값(숫자, 문장열), 객체 포인터를 포함한 정적 데이터가 저장되는 곳이다.

    스택 메모리의 크기 제한은 stack_size V8 플래그 값을 사용하여 설정할 수 있다.

     

    V8 메모리 사용(Stack, Heap)

    class Employee {
        constructor(name, salary, sales) {
            this.name = name;
            this.salary = salary;
            this.sales = sales;
        }
    }
    
    const BONUS_PERCENTAGE = 10;
    
    function getBonusPercentage(salary) {
        const percentage = (salary * BONUS_PERCENTAGE) / 100;
        return percentage;
    }
    
    function findEmployeeBonus(salary, noOfSales) {
        const bonusPercentage = getBonusPercentage(salary);
        const bonus = bonusPercentage * noOfSales;
        return bonus;
    }
    
    let john = new Employee("John", 5000, 5);
    john.bonus = findEmployeeBonus(john.salary, john.sales);
    console.log(john.bonus);

    위 코드는 Stack과 Heap 메모리 사용 과정을 이해하기 위한 예시 코드이며 다음과 같은 동작을 수행한다.

    • Employee라는 클래스가 있고, 해당 클래스에는 constructor가 존재한다.
      • constructor 메서드는 객체를 생성하고 초기화하는 역할을 하며 예시 코드에서는 name, salary, sales를 인자로 받아와 객체 property의 값으로 저장한다.
    • BONUS_PERCENTAGE라는 이름의 전역 변수가 존재하고, 원시값 10을 저장하고 있다.
    • getBonusPercentage() 함수는 salary를 가지고 보너스 퍼센트를 구하는 함수다.
      • 해당 함수에서는 salary 인자를 받아서 percentage 전역 변수에 저장 및 일련의 계산을 거쳐 return 하는 역할을 한다.
    • findEmployeeBonus() 함수는 보너스 퍼센트를 적용한 실제 금액 구하는 함수다.
      • 해당 함수는 두개의 인자를 받고, 지역 변수에 저장 및 두 수를 곱해 값을 return 한다.
    • new 생성자를 통해 john이라는 객체를 생성하고, name, salary, sales 파라미터에 값을 저장한다.
    • 생성된 john 객체에 bonus property를 생성하고, findEmployeeBonus() 함수를 통해 보너스를 계산하여 값을 저장한다.
    • 마지막으로 console.log()를 통해 john의 보너스를 출력한다.

     

    이러한 JavaScript 코드를 실행할 때 V8 메모리가 어떻게 동작하는지 알아본다.

    1. 초기 메모리

    Global fame은 class인 Employee와 함수 findEmployeeBonus, getBonusPercentage가 저장되어 heap의 코드를 가리킨다.

    Class와 Function은 객체 타입으로 같은 heap에 생성되고, Stack Pointer를 사용하여 heap에서 stack을 참조한다.

    함수들은 JavaScript에서 객체로 분류되고, 전역 스코프에도 적용된다.

     

    스코프는 변수가 영향을 미치는 범위, 혹은 변수의 유효범위 라고 할 수 있다. 블록{ }내부를 지역 스코프, 블록{ }밖을 전역 스코프라고 표현한다.

     

    2. 원시값 저장

    int, string과 같은 모든 원시 타입의 값은 스택에 저장된다.

    이는 전역 스코프에서도 적용되므로 BONUS_PERCENTAGE에 10을 저장하게 될 경우 스택의 Global frame에 저장되게 된다.

     

    3. john 객체 생성

    다음으로 new 생성자를 통해 john이라는 객체를 만드는 과정이다.

    Employee 클래스에 정의된 constructor() 메서드가 실행되고, 호출할 때 넘긴 인자값이 object 형태로 저장된다.

    현재 메모리상에 표현되지 않은 이유는 consturctor() 메서드가 실행되지 않았기 때문이다.

     

    4. constructor() 실행

    constructor() 메서드가 실행되면서 stack frame에 저장된 지역 변수인 name, salary, sales를 heap에 할당된 object 공간에 저장한다.

     

    5. constructor() 메서드 실행 이후 return

    constructor() 메서드 실행 이후 heap에 할당된 object를 가리키는 주소를 반환한다.

     

    6. return 이후

    return 이후에는 앞서 지역 변수 저장을 위해 사용되었던 stack frame을 지우고, 반환된 object 주소를 john 전역 변수에 저장한다.

    이로 인해 Global frame에 john이 저장된다.

     

    7. john 객체에 bonus property 추가

    다음으로 john의 bonus property를 추가하기 위해 findEmployeeBonus() 함수가 호출되면 그림과 같이 stack에 frame이 생성된다.

     

    8. getBonusPercentage() 함수 실행 과정

    getBonusPercentage() 함수는 지역 변수인 percentage에 퍼센트 계산값을 저장하고, 해당 값을 return한다.

     

    9. findEmployeeBonus() 내 bonusPercentage 지역변수에 return 값 저장

    return 이후에는 stack frame을 삭제하고, findEmployeeBonus의 stack frame에 bonusPercentage 지역변수에 값을 저장한다.

     

    10. findEmployeeBonus() return

    이후 보너스 금액을 구하는 과정을 거쳐 return하게 되고,

     

    11. findEmployeeBonus() return 이후

    return 이후 stack frame이 삭제되면서 heap에 위치한 john 객체에 bonus property의 value를 저장한다.

     

    기존 x86-64 OS에서 메모리를 관리하는 방법과 유사하지만 몇가지 특징이 있다.

    1. 전역 스코프는 스택에서 "전역 프레임(Global frame)"에 보관된다.
    2. Class, Function과 같은 객체 타입은 heap에 할당된다.
    3. 함수들은 JavaScript에서 객체로 분류되고 전역 스코프에도 추가된다.

     

    V8 메모리 관리: 가비지 컬렉션

    V8은 heap 메모리 관리를 위해 가비지 컬렉션 이용한다.

    • Garbage Collection(GC) : 참조가 없는 객체들이 사용하는 메모리를 비워서 새로운 객체를 생성하기 위한 공간을 만드는 역할을 수행
    • 참조 없는 객체 : 스택으로부터 더 이상 직접 혹은 간접적으로 참조되지 않는 객체를 의미함

     

    Minor GC(Scavenger)

    Minor GC Overview

    New space의 Semi space는 To, From으로 두 영역으로 나뉜다.

    새로운 object 생성시 To -> From 영역으로 object들을 이동시키고, 이동중에는 참조되지 않는 object(즉, Garbage)를 삭제한다.

    이후 새로운 object를 From영역에 추가한다.

    Minor GC - From space에 object를 추가할 공간이 없을때

    계속해서 새로운 object를 할당할 때 마다 From space에 생성되게 되는데, 이 과정을 거치다보면 From space에 추가할 공간이 없어지게된다. 이때 오랜된 object를 Old space로 이동하고 나머지 object들을 To space로 이동시킨다.

     

    Minor GC - Orphan 삭제 및 10번 new object 할당

    이동 과정에서 From space에 있는 Orphan 즉, 누구에게도 참조되지 않는 object를 삭제하며 새롱운 object를 추가한다.

    • Minor GC는 Stop-the-world 프로세스지만, 빠르고 효율이 좋다는 평을 받음
    • Scanvenger 알고리즘을 사용하며 이는 비교적 크기가 작은 heap 메모리를 관리할 때 적합함

     

    Major GC

    • Old Space를 작고 깨끗하게 유지
    • Mark-Sweep-Compact 알고리즘을 사하며 이는 크기가 비교적 큰 heap 메모리에 적합함
    • Tri-Color(흰색-회색-검은색) 마킹 시스템을 사용
      • 해당 시스템은 3단계의 프로세스를 거치며 마지막인 세번째 단계에서는 조각화 휴리스틱에 따라 실행됨
    • 마킹 -> 스위핑 -> 압축 프로세스로 진행

    Reference

    반응형
Designed by Tistory.