[C++ 공부] 메모리 관리 (1) - 용어 정리

Yujin Lee·2022년 2월 24일
0

Cpp_Study

목록 보기
8/8
post-thumbnail

이번 포스팅에서는 C++ 메모리 관리를 더 깊이 살펴보기 전에 알아야할 개념을 먼저 살펴본다.

가상 메모리, 가상 메모리 공간, 스택 메모리, 힙 메모리, 페이징


1. 컴퓨터 메모리

컴퓨터의 물리적 메모리는 시스템에서 실행되는 모든 프로세스가 공유한다. 하나의 프로세스가 너무 많은 메모리를 차지하면 대부분의 다른 프로세스가 영향을 받게 된다. 하지만 저자는 프로그래머한테 있어서 그게 머ㅜ 어쩔티비라 한다. 오... 여하튼 이렇게 격리된 메모리는 가상 메모리로 정의되고, 마치 프로세스가 모든 메모리를 자신을 위해 보유하는 것처럼 보이게 만든다. 각각의 프로세스는 자신만의 가상 주소 공간을 가진다.

1.1 가상 주소 공간

프로그래머가 보게 되는 가상 주소 공간 내의 메모리 주소는 OS와 프로세서의 일부인 메모리 관리자(MMU : Memory Management Unit) 에 의해 물리적 메모리 주소와 매핑된다. 이러한 매핑이나 변환은 메모리에 접근할 때마다 발생한다.

가상 메모리는 프로세스가 물리적 주소 공간보다도 큰 가상 주소 공간을 가질 수 있게 한다. 왜냐하면 가상 메모리가 실제로 물리적 메모리를 반드시 확보하고 있어야 하는 것은 아니기 때문이다.

가상 ㅁ모리 주소는 실제 물리적 메모리 주소와 다르다.


1.2 메모리 페이지

1.2.1 메모리 페이지(memory page)

오늘날 가상 메모리를 구현하는 가장 일반적인 방법은 메모리 페이지 라고 부르는 고정된 크기의 블록으로 주소 공간을 나누는 것이다.

1.2.2 페이지 폴트(page fault)

메모리 페이지가 주 메모리에 매핑돼 있지 않으 경우 발생하는 하드웨어 예외

1.2.3 페이징(paging)

주 메모리에 더 이상 쓸 수 있는 페이지 프레임이 없으면 정리를 좀 해야한다. 이 때 정리될 페이지가 사용된 것이라면, 즉 디스크에서 로드된 이후 수정된 적이 있다면 바꾸기 전에 디스크에 기록해야 한다. 이 과정을 페이징(paging)이라고 한다.


1.3 스레싱

스레싱(thrashing)은 시스템의 물리적 메모리가 넉넉하지 못한 상태에서 발생하므로 지속적인 페이징을 야기한다. 이렇게 새로운 메모리 페이지를 로딩한다는 건 다른 페이지가 디스크에 저장돼야 한다는 것이다. 데이터를 디스크에서 메모리로 다시 가져오거나 기록하는 작업은 매우 느린데, 이는 시스템이 페이징에 시간을 많이 소비하기 때문이다.



2. 프로세스 메모리

스택(stack)힙(heap) 은 C++ 프로그램의 메모리 세그먼트에 가장 중요한 두 가지 요소다.

  • 스택
    스택은 지역 변수가 위치하는 곳이며, 함수의 인수도 포함된다.
    함수가 호출될 때마다 증가하고 함수가 반환되면 감소한다.
    각각의 스레드는 자신만의 스택을 가지고 있으므로 스택 메모리는 스레드 안전을 지원한다.

  • 힙은 전역 메모리 영역이고, 프로세스 내의 모든 스레드가 공유한다.
    new를 사용해 메모리를 할당할 때마다 커지고, delete를 사용해 메모리를 해제할 때 감소한다.

보통 힙은 작은 수의 주소에서 시작해서 위로 증가하며, 스택은 큰 수의 주소에서 시작해서 낮은 방향으로 늘어난다.


2.1 스택 메모리

  • 연속적인 메모리 블록이다.
  • 고정된 최대 크기를 가진다. ※조심하자 -> 프로그램이 최대 스택 크기를 초과하면 비정상 종료된다.
  • 절대로 조각나지(=파편화, fragmented) 않는다.
  • 스택에 메모리를 할당하는 것은 항상 빠르다.
  • 프로그램의 개별 스레드는 자신만의 스택을 가진다.

중요한 건 프로그램이 비정상 종료되게 만드는 스택 메모리 초과 문제를 유발하지 않아야 한다는 것이다. 또한, 언제나 메모리의 요청과 해제는 스택의 최상단(연속된 메모리의 끝단)에서 수행된다. 스택 메모리는 결코 파편화되지 않으며 스택 포인터를 이동시키는 것만으로 메모리를 할당하거나 해제할 수 있다는 것이다.

스택 오버플로(stack overflow) 가 발생하는 가장 흔한 이유는 지나친 재귀 호출(recursive call)이나 스택에 할당되는 자동 변수를 많이 사용하는 경우이다.


2.2 힙 메모리

힙은 C++ 관점에서 동적 저장소가 실제 의미에 더 가깝고, 데이터가 동적으로 위치하는 공간이다. 힙은 여러 스레드에 의해 공유되는데, 힙을 사용하는 메모리 관리는 동시 처리성을 지원해야 한다. 순차적인 스택과 달리 힙은 동적이므로 메모리 할당과 해제가 임의로 발생한다. 동적 객체의 수명과 가변적 크기로 할당되는 과정은 메모리가 파편화될 위험이 있다.


메모리가 파편화될 위험이란 무엇인가? 다음을 살펴보자.
예를 들어 16KB의 메모리 블록에 메모리를 할당한다고 해보자.
1KB의 A 타입과 2KB의 B 타입을 번갈아 가며 할당한다.

자 이제, A는 필요가 없어졌다. 모두 해제한다.
그럼 메모리는 다음과 같이 될 것이다.

분명 남은 공간은 6KB이기 때문에 B를 좀 더 할당할 수 있을 것으로 보였으나,
메모리가 파편화되었기 때문에 2KB 크기의 메모리 블록을 찾을 수 없다.

profile
I can be your Genie🧞‍♀️ How ‘bout Aladdin? 🧞‍♂️

0개의 댓글