[CS] Memory (Stack & Heap)

sarang_daddy·2023년 1월 13일
0
post-thumbnail

Intro

컴퓨터에서 프로그램이 빠르게 돌아가기 위해서는 메모리가 필요하다고는 알고 있었지만,
왜? 라는 이유에 대해서는 생각을 해보지 않았다.
이번에는 메모리의 구조와 역할을 공부해보면서 그 이유를 조금은 이해해보고자 한다.

📑 참고자료

V8 엔진에 대한 개념
메모리구조
메모리 C++
자바스크립트 메모리 할당
Stack & Heap
Call Stack and Memory Heap
콜스텍과 힙 차이
자바스크립트의 동작원리: 엔진, 런타임, 호출 스택
16bit Virtual Machine
stack vs heap
Stack과 Heap에 저장되는 과정
스택과 힙에 대한 자세한 설명 1
스택과 힙에 대한 자세한 설명 2

메모리 구조

운영체제는 프로세스를 실행할 때 마다 관리하는 메모리를 할당하고 할당된 메모리는 위 그림과 같이 역할별로 영역이 나눠진다.

1. TEXT 영역

  • 프로그램을 실행하기 위해 저장되어 있는 영역이다.
  • 프로그램에 있는 함수 코드, 제어문, 상수 등을 포함한다. (명령문)
  • 일반적으로 한 번 로딩하면 바뀌지 않는다.

2. GVAR/BSS 영역 (DATA 영역)

  • 범위(Scope)가 정해지지 않는 전역(Global 또는 Static) 변수를 포함한다.
  • 프로그램 실행 전에 선언되어 프로그램 종료까지 메모리에 남아있는 변수들이다.
  • GVAR 는 초기값을 0이 아닌 특정한 값으로 지정한 경우 사용한다.

3. HEAP 영역

  • 사용자에 의해 관리되는 영역이다.
  • 동적으로 할당되는 메모리 공간으로 malloc 이나 new 명령으로 할당한다.
  • ex) Class, 참조변수
  • 힙 영역에 할당한 메모리 공간에 대한 주소를 스택에 있는 포인터 변수로 참조하는 경우가 많다.

4. STACK 영역

  • 함수를 호출할 때마다 지역 변수, 매개변수와 리턴값 등이 저장되는 공간이다.
  • 함수가 종료되면 해당 함수에 할당된 변수들을 메모리에서 헤체시킨다. (stack - pop 구조)
  • 재귀 함수 등으로 할단된 Stack 메모리영역을 넘어버리면 Stack Overflow가 발생된다.

STACK & HEAP

Call Stack(호출 스택)

스택은 메모리 영역 중 일부로, main() 함수를 포함한 각 함수의 지역변수가 저장되는 공간이다. ‘무더기’, ‘쌓이다’라는 단어의 의미처럼, 변수가 생성될 때 생성된 순서대로 차곡차곡 쌓인다.

스택에 쌓이는 변수에는 객체의 좌표를 저장하기 위하 공간만 존재하며 이를 참조 변수(Reference Variable)이라고 하며, 객체의 좌표값은 참조값(Reference Value)라고 부른다.

스택은 메서드와 함수 프레임, 원시 값, 객체 포인터를 포함한 정적 데이터가 저장되는 곳이다.

함수에서 새로운 변수를 선언할 때마다 해당 변수는 스택에 쌓인다. 함수가 종료되면 해당 함수에 의해 쌓인 변수는 스택에서 사라진다(해제된다). 따라서 해당 공간에는 다른 변수들이 쌓일 수 있게 된다.

함수실행이 끝나면 스택에 쌓인 변수들 사라진다.

function multiply(x, y) {
  return x * y;
}
function printSquare(x) {
  var s = multiply(x, x);
  console.log(s);
}
printSquare(5);

위 그림은 호출 스택의 각 단계를 보여주는 스택 프레임이다.

위 그림처럼 콜백함수 등의 문제로 호출 스택의 허용치를 넘기면 오버플루오가 발생하여 에러가 나온다.

Memory Heap (힙 메모리)

변수가 차곡차곡 쌓이는 형태인 스택 영역과는 달리, 힙 영역에는 임의의 위치에 객체가 생성된다(dynamic allocation). 따라서 어떤 객체의 프로퍼티에 값을 저장하거나 저장된 값을 가져오고 싶으면, 그 객체의 힙 영역상 좌표를 알고 있어야 한다.

V8엔진(JS)은 힙 메모리에 객체나 동적 데이터를 저장한다.

스택에 쌓이는 참조변수의 경우 함수가 끝나면 스택에서 해제되지만, 참조변수가 가리키고 있는 객체는 힙에서 지워지지 않는다. 즉, 힙 영역에 생성한 변수는 어느 블록에서 생성했던 간에 블록을 빠져나와도 힙에 유지된다.

힙 변수는 스택변수처럼 지역변수가 아닌 전역변수이며,힙 영역을 두면 하나의 객체를 여러 참조변수에서 공유하는 형태로 사용할 수 있어 훨씬 메모리 공간을 절약할 수 있게 된다.

힙은 자유롭게 떠있는 공간에 가깝고 스택보다 크다. 다만 스택처럼 CPU에 의해 타이트하게 관리되지 않고 힙에 쓸 수 있는 변수크기에 제한이 없기 때문에 memory leak 발생의 위험이 있다.

가비지 컬렉션

힙 영역은 매우 넓어서, 객체의 위치를 기억하는 참조 변수가 모두 사라지면 바다 위의 무인도처럼 찾지 못하는 섬이 된다. 객체는 분명 힙 영영 어딘가에 존재하지만 위치를 모르기 때문에 다시는 찾을 수 없다. 이렇게 미아가 된 객체는 메모리 공간이 부족해질 정도까지 쌓이면 가비지 컬렉션이라는 기능에 의해 소멸한다.

V8엔진(JS)은 가비지 컬렉션을 사용해 힙 메모리를 관리한다.
가비지 컬렉션은 참조 없는 객체들이 사용하는 메모리를 비워서 새로운 객체를 생성하기 위한 공간을 만드는 역할을 한다.
가비지컬렌션 정리 추천글

힙 메모리의 영역

  • New space
    "Young 제너레이션"이라고도 하며 새로 만들어진 모든 객체를 저장한다.
    이 영역은 크기가 작고 짧은 생명 주기를 가진다.

  • Old space
    "Old 제너레이션"이라고도 하며 "New 영역"에서 살아남은 객체들이 이동하는 영역이다.
    이 영역은 다시 2개의 영역으로 나누어진다.
    Old 포인터 영역: 살아남은 객체들을 가지며, 이 객체들은 다른 객체를 참조한다.
    Old 데이터 영역: 데이터만 가진 객체들(다른 객체를 참조하지 않는다)을 가진다.

  • 라지 오브젝트 영역
    다른 영역의 제한된 크기보다 큰 객체들이 살고 있는 영역이다.
    각 객체는 자체 mmap 메모리 영역을 갖는다. 라지 오브젝트들은 가비지 컬렉터로 이동하지 않는다.

  • 코드 영역
    실시간(JIT) 컴파일러가 컴파일된 코드들을 저장하는 곳이다.
    유일하게 실행 가능한 메모리가 있는 영역이다.

  • 셀 영역, 속성 셀 영역, 맵 영역
    이 영역들은 각각 Cells, PropertyCells, Maps을 포함한다. 각 영역은 모두 같은 크기의 객체들을 포함하며, 어떤 종류의 객체를 참조하는지에 대한 제약이 있어서 수집을 단순하게 만든다.

STACK VS HEAP

STACKHEAP
메모리는 연속블럭으로 할당된다.메모리는 랜덤하게 할당된다.
빠르게 접근할수있다.스택보다 접근속도가 느리다
로컬변수에만 접근한다.전역변수에 접근한다.
변수들의 크기 조정이 불가능하다.변수들의 크기를 조정할수 있다.
코스트가 적다.코스트가 더 많이 든다.
메모리가 부족할 수 있다.메모리 분열이 발생 할 수있다.
고정된 메모리 크기를 가진다.메모리 크기가 유동적이다.
스택은 선형적이다.힙은 계층적이다.
컴파일러 명령으로 오토메틱하다.프로그래머의 메뉴얼을 따른다

스택의 장점 & 단점

👍 구현이 쉽다.
👍 힙보다 접근이 쉽다
👍 할당 및 해제는 컴파일러에의해 자동으로 수행된다.
👍 안정되고 안전하다.


👎 스택은 제한된 메모리다.
👎 스택은 유연하지 못하다.
👎 할당된 메모리 크기를 변경 할 수 없다.
👎 랜점 엑세스가 불가능하다.

힙의 장점 & 단점

👍 힙은 유연하다
👍 프로그래머가 메모리 공간을 할당 및 해제 할 수 있다.
👍 전역 변수에 접근 할 수 있다.
👍 메모리 크기의 제한이 없다.


👎 힙 프레임 처리는 스택 프레임 처리보다 비용이 크다.
👎 힙 메모리의 크기는 상당히 크다.
👎 메모리 누수의 위헙이 있다.
👎 스택보다 접근이 느리다.

Outro

스택이 좋다 힙이 좋다라는 결론은 내릴 수 없다.
둘 모두 메모리를 효율적으로 사용하기 위한 기능이며 프로그래머는 스택과 힙과 같은 메모리의 구조와 역할을 고려하여 더욱 효율성이 좋은 개발을 할 수 있도록 하자.

profile
한 발자국, 한 걸음 느리더라도 하루하루 발전하는 삶을 살자.

0개의 댓글