일반적인 프로세스 메모리 구조

일반적인 프로세스 메모리 모델은 프로그램이 실행되는 동안 사용하는 메모리의 구조
- 코드(텍스트) 섹션
- 실행할 프로그램 코드가 저장되는 영역
- 보통 읽기 전용으로 설정되어 있어 실행 중에 코드가 변경되지 않도록 함
- 데이터 섹션
- 초기화된 전역 변수 및 정적 변수가 저장되는 영역
- 프로그램 시작 시 초기값을 가지고 있음
- 초기화된 데이터 섹션: 초기값을 가진 변수
- 초기화되지 않은 데이터 섹션(BSS: Block Started by Symbol): 초기값이 없는 변수. 실행 시 0으로 초기화
- 힙(Heap)
- 동적으로 할당되는 메모리 영역
- 런타임 시 동적으로 크기가 변경될 수 있음
- 메모리 할당 및 해제를 관리하기 위해 malloc, free 등의 함수를 사용
- 스택(Stack)
- 함수 호출과 관련된 지역 변수 및 매개변수가 저장되는 영역
- 함수 호출 시 스택 프레임이 생성되고, 함수가 종료되면 해당 스택 프레임이 제거
- 메모리 매핑 영역(Memory-Mapped Region)
- 동적 라이브러리와 파일 매핑 등이 저장되는 영역
- 프로그램 실행 중 필요한 파일을 메모리에 매핑하여 사용 가능
Node.js에서의 프로세스 메모리 관리
Node.js는 V8 자바스크립트 엔진을 기반으로 하는 서버 사이드 런타임. V8 엔진은 C++로 작성되어 있으며, 메모리 관리 방식도 일반적인 프로세스 메모리 모델과 유사하지만, 자바스크립트의 특성에 맞게 최적화되어 있음
- 코드 섹션
- Node.js 애플리케이션의 자바스크립트 코드가 저장되는 영역
- 데이터 섹션
- Node.js 내에서 사용되는 전역 변수 및 정적 변수가 저장되는 영역
- 힙(Heap)
- V8 엔진의 가비지 컬렉션(Garbage Collection)에 의해 관리되는 메모리 영역
- 자바스크립트 객체와 배열, 함수 등의 동적 메모리 할당이 이루어짐
- 가비지 컬렉션이 주기적으로 불필요한 메모리를 해제하여 메모리 누수를 방지
- 스택(Stack)
- 함수 호출 시 생성되는 실행 컨텍스트가 저장됨
- Node.js는 비동기 프로그래밍 모델을 사용하기 때문에 콜백 함수와 이벤트 루프가 중요하게 작용
- 네이티브 메모리(Native Memory)
- Node.js는 네이티브 모듈과 애드온을 사용할 수 있음
- 이러한 모듈은 네이티브 코드(C/C++)로 작성되어 별도의 메모리 영역을 사용할 수 있음
Node.js의 메모리 관리와 일반적인 프로세스 메모리 모델의 차이점
- 가비지 컬렉션: Node.js는 V8 엔진의 가비지 컬렉션을 사용하여 메모리를 관리함. 자바와 같이 heap에서 메모리가 누수나는 일이 없이 가비지 컬렉션이 알아서 메모리 관리를 해줌. 일반적인 C/C++ 프로그램에서는 프로그래머가 명시적으로 free나 delete를 호출해야야 함
- 비동기 프로그래밍: Node.js는 이벤트 루프와 비동기 콜백을 통해 비동기 프로그래밍을 지원. 이는 스택 메모리 사용에 영향을 주어, 콜백 함수가 비동기로 호출될 때 별도의 실행 컨텍스트가 생성됨
- 네이티브 애드온: Node.js는 네이티브 코드로 작성된 모듈을 사용할 수 있어, 이들 모듈은 별도의 네이티브 메모리 영역을 사용할 수 있음
Node.js에서 가상 메모리 관리
Node.js는 V8 자바스크립트 엔진을 사용하여 가상 메모리를 관리함.
V8은 자바스크립트 코드 실행을 최적화하기 위해 여러 가지 메모리 관리 기법을 사용
메모리 예약 및 할당
- V8은 처음에 OS로부터 큰 메모리 블록을 예약
- 이 블록은 힙 영역과 유사하며, 자바스크립트 객체, 함수, 배열 등이 이 영역에 저장됨
- 힙은 new_space와 old_space로 나뉨
- new_space는 짧은 생명 주기를 가진 객체를 저장하고, old_space는 오래 살아남은 객체를 저장함
Node.js에서 가비지 컬렉션(GC) 동작 방식
가비지 컬렉션 알고리즘
- Scavenger (Scavenge GC): 젊은 객체(new_space)에 대한 가비지 컬렉션. 두 개의 반공간(Semi-space)을 사용하여 객체를 복사하며 살아남은 객체만 다른 반공간으로 이동
- new_space에 있는 객체는 두 개의 반공간에 분배됨
- 객체가 할당될 때 한 반공간에만 할당
- 가비지 컬렉션이 실행되면 살아남은 객체를 다른 반공간으로 복사하고, 이전 반공간을 비움
- Mark-Sweep & Mark-Compact: 오래된 객체(old_space)에 대한 가비지 컬렉션. 마킹 단계에서 접근 가능한 객체를 표시하고, 스위핑 단계에서 마킹되지 않은 객체를 해제. 필요시 메모리 단편화를 줄이기 위해 컴팩트 단계를 수행하여 객체를 압축
- Mark-Sweep
- 힙의 old_space에서 실행됨
- 마킹 단계: 루트 객체에서 시작하여 접근 가능한 모든 객체를 마킹
- 스위핑 단계: 마킹되지 않은 객체를 해제하여 메모리를 확보
- Mark-Compact:
- 메모리 단편화를 방지하기 위해 사용
- 마킹 단계 후, 살아남은 객체를 힙의 한쪽 끝으로 이동하여 메모리 블록을 압축
- Mark-Sweep
힙 메모리 단편화 및 효율적인 메모리 관리
힙 메모리 단편화
힙 메모리에 객체를 자주 생성하고 해제하다 보면 메모리 단편화가 발생할 수 있다. 이는 메모리 블록이 작게 나뉘어져 할당 가능한 연속된 큰 메모리 블록이 부족해지는 현상으로 malloc 호출이 실패할 수 있음.
효율적인 메모리 관리 방법
- 메모리 풀링:
- 자주 사용되는 객체를 미리 할당해두고 재사용하는 기법
- 메모리 할당과 해제의 빈도를 줄여 단편화를 방지
- 객체 크기 최적화:
- 객체의 크기를 최소화하여 메모리 사용을 줄임
- 큰 객체보다는 작은 객체를 자주 할당하는 것이 메모리 관리에 유리함
'JS' 카테고리의 다른 글
| Jest를 통해 unit테스트 진행하기 (1) | 2024.07.24 |
|---|---|
| 타입스크립트 컴파일 with readline (2) | 2024.07.23 |
| [Node.js] Process 노드 모듈 (0) | 2024.07.19 |
| XML파일과 JSON파일 (0) | 2024.07.17 |
| readline을 통해 입력받기 (0) | 2024.07.15 |