동적 할당

namu·2022년 10월 11일

메모리 구조 복습

낮은 주소
코드 영역
데이터 영역
힙 영역(런 타임에 크기가 결정됨)
스택 영역(컴파일 타임에 크기가 결정됨)
높은 주소

실행할 코드가 저장되는 영역 -> 코드 영역
전역(global)/정적(static) 변수 -> 데이터 영역
지역 변수/매개 변수 -> 스택 영역
동적 할당 -> 힙 영역

지금까지 데이터 영역/ 스택 영역 이용해서
이런 저런 프로그램을 잘 만들어 왔다!
굳이 새로운 영역이 필요할까?

실제 상황)
MMORPG 동적 1명~5만명, 몬스터 1마리~500만마리

몬스터 500만마리를 스택에 할당하려하면, Stack overflow 발생.
Stack은 주로 함수들끼리 인자를 주고받는 용도로 쓰게 만들어진 영역.
몬스터 500만마리를 전역으로 정의하면, 항상 최대 상한선에 맞추어 메모리를 잡아야 함.

스택 영역
함수가 끝나면 같이 정리되는 불안정한 메모리
잠시 함수에 매개변수 넘긴다거나, 하는 용도로는 OK

메모리 영역
프로그램이 실행되는 도중에는 '무조건' 사용됨.

희망사항)
필요할 때만 사용하고, 필요없으면 반납할 수 있는!
그러면서도 (스택과는 다르게) 우리가 생성/소멸 시점을 관리할 수 있는!
-> HEAP

동적할당과 연관된 함수/연산자 : malloc, free, new, delete new[], delete[]

유저 영역 [메모장][LOL] [곰플레이어]
커널 영역 (Windows 등의 핵심 코드)

유저 영역) 운영체제에서 제공하는 API 호출
커널 영역) 메모리 할당해서 건내줌

실제로는 요청한 크기만큼만이 아닌, 큰 메모리를 주고, 거기서 잘라서 씀.
커널에 요청하는 횟수가 많아지는 것을 방지하기 위해.

C++에서는 기본적으로 CRT(C런타임 라이브러리)의 [힙 관리자]를 통해 힙 영역 사용
단, 정말 원한다면 우리가 직접 API를 통해 힙을 생성하고 관리할 수도 있음 (MMORPG 서버 메모리 풀링)

void* pointer = malloc(1000);
CRT의 [힙 관리자]를 통해 관리됨.

malloc
할당할 메모리 크기를 건내준다.
메모리 할당 후 시작 주소를 가리키는 포인터를 반환해준다 (메모리 부족 NULL).

void 포인터는?
별이 있으니 포인터 (주소를 담는 바구니)
타고 가면 void 뭐가 있는지 모르겠으니까, 너가 적당히 변환해서 사용해라.

Monster m1 = (Monster)pointer;
할당받은 메모리를 Monster 용도로 사용하겠다!

free
malloc (혹은 calloc, realloc 등)을 통해 할당된 영역을 해제
힙 관리자가 할당/미할당 여부를 구분해서 관리

free할 때 사이즈를 인자로 넣지 않는 이유는 사이즈를 이미 알고 있기 때문인데,
실제로 메모리를 할당할 때, 앞에 헤더를 넣는데, 그곳에 메모리의 사이즈 관련 정보가 들어있다.
이렇게 메모리에 힌트를 넣는 방법도 있고, 따로 테이블로 관리하는 방법도 있다.

Heap Overflow
유효한 힙 범위를 초과해서 사용하는 문제

free를 안하는 경우에는 memory leak. 프로그램 전체가 가용할 수 있는 메모리 용량을 벗어나서 crash.

free를 여러번 하는 경우에는 Double Free. 대부분 그냥 크래시만 나고 끝난다.
free하게 되면, 디버그 모드에서는 dddddddd로 메모리를 밀게 되는데, 이 상태에서 free를 또하면, 힌트로 사용하는 메모리 헤더에 들어있는 사이즈 정보를 dddddddd로 읽게 됨.

Use-After-Free
바로 크래시가 나면 다행, 유효한 상태의 다른 의미로 쓰이는 메모리의 값을 엉뚱한 값으로 수정한다면, 큰 일.

new / delete
C++에 추가됨
malloc/free는 함수! new/delete는 연산자(operator)

근본적인 차이
new/delete는 (생성타입이 클래스일 경우) 생성자/소멸자를 호출해준다!!!
malloc/free는 따로 호출해주는 방법이 있음.
new[]/delete[]는 생성자/소멸자 n번 호출됨.

profile
안녕하세요

0개의 댓글