A. 메모리의 기초
프로그램이 실행 되기 위해서 먼저 프로그램이 메모리에 로드 되어야 함
또한 프로그램 속 변수를 저장할 메모리도 필요함
따라서 운영체제는 프로그램 실행을 위해 아래와 같은 메모리 공간을 제공
1. 메모리의 구조
a. 코드 영역
🌟 실행할 프로그램의 코드가 저장되는 영역 (텍스트 영역)
CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리
b. 데이터 영역
🌟 프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역
프로그램 시작 = 할당 / 프로그램 종료 = 소멸
c. 힙 영역
🌟 프로그래머가 할당( = 동적 할당) / 해제 (자바에서는 가비지 컬렉터가 자동 해제) 하는 메모리 공간
- 클래스, 클로저가 이 부분에 해당, 런타임 시에 크기가 결정
- 낮은 주소에서 높은 주소의 방향으로 할당
d. 스택 영역
🌟 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 프로그램이 자동으로 사용하는 임시 메모리 영역
- 함수의 호출 = 할당/ 함수의 호출 완료 = 소멸
- 푸시(push) 동작으로 데이터를 저장하고, 팝(pop) 동작으로 데이터를 인출
- 후입선출(LIFO, Last-In First-Out) 방식에 따라 동작
- 높은 주소에서 낮은 주소의 방향으로 할당
- 스택 영역에 저장되는 함수의 호출 정보를 스택 프레임(stack frame)이라고 함
B. 힙 영역
1. 메모리의 동적 할당(dynamic allocation)
a. malloc() 함수
🌟 프로그램이 실행 중일 때 사용자가 직접 힙 영역에 메모리를 할당
- 메모리 크기에 맞고, 아직 할당되지 않은 적당한 블록을 찾아 첫 번째 바이트를 가리키는 주소 값을 반환함
- 적당한 블록이 없을 때에는 널 포인터를 반환
- 주소값을 반환하기 때문에 힙 영역에 할당된 메모리 공간으로 접근하려면 포인터를 사용해야 함
📘 문법
#include <stdlib.h>
void *malloc(size_t size);
//size : 할당받고자 하는 메모리의 크기를 바이트 단위로 전달
// size_t 타입은 부호없는 정수라고 이해
b. free() 함수
🌟 힙 영역에 할당받은 메모리 공간을 다시 운영체제로 반환해 주는 함수
데이터 영역이나 스택 영역에 할당되는 메모리의 크기는 컴파일 타임에 결정되어, 프로그램이 실행되는 내내 고정
하지만 메모리의 동적 할당으로 힙 영역에 생성되는 메모리의 크기는 런 타임 내내 변화
따라서 free() 함수로 메모리를 해제해 줘야 함 / 메모리가 부족해지는 현상 = 메모리 누수(memory leak)
📘 문법
#include <stdlib.h>
void free(void *ptr);
//*ptr : 해제하고자 하는 메모리 공간을 가리키는 포인터
// void형 포인터로 선언되어 어떠한 타입의 포인터라도 인수로 전달
🤓 예제 : 크기가 고정된 배열이 아닌 런 타임에 크기가 결정되는 배열 만들기
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
int arr_len = 3;
int* ptr_arr;
ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당
if (ptr_arr == NULL) // 메모리의 동적 할당이 실패할 경우
{
printf("메모리의 동적 할당에 실패했습니다.\n");
exit(1);
}
printf("동적으로 할당받은 메모리의 초기값은 다음과 같습니다.\n");
for (i = 0; i < arr_len; i++)
{
printf("%d ", ptr_arr[i]);
}
free(ptr_arr); // 동적으로 할당된 메모리의 반환
return 0;
}
✨ 실행결과
동적으로 할당받은 메모리의 초기값은 다음과 같습니다.
0 0 0
c. calloc() 함수
🌟 힙 영역에 메모리를 동적으로 메모리의 크기를 두 개의 인수로 나누어 전달받아 할당해주는 함수
- 메모리를 할당받은 후에 해당 메모리의 모든 비트값을 전부 0으로 초기화
- free() 함수를 통해 할당받은 메모리를 해제
📘 문법
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
//첫 번째 인수 : 메모리 블록의 개수
//두 번째 인수 : 각 블록의 바이트 수
👉 즉, 힙 영역에 size 크기의 메모리 블록을 nmemb개 할당받을 수 있도록 요청
🤓 예제 : malloc(), calloc()이같은 동작을 수행하게 함
1. ptr_arr = (int*) malloc(arr_len * sizeof(int));
2. ptr_arr = (int*) calloc(arr_len, sizeof(int));
d. realloc() 함수
🌟 이미 할당된 메모리의 크기를 바꾸어 재할당할 때 사용하는 함수
- 첫 번째 인수로 NULL이 전달되면, malloc() 함수와 정확히 같은 동작
- 기존의 메모리 위치에 충분한 공간이 있다면 바로 이어서 추가 메모리 공간을 할당
- 기존의 메모리 위치에 충분한 공간이 없으면 메모리의 다른 공간에 기존의 데이터를 복사한 후, 이어서 추가 메모리 공간을 할당
📘 문법
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
//첫 번째 인수 : 크기를 바꾸고자 하는 메모리 공간을 가리키는 포인터
//두 번째 인수 : 해당 메모리 공간에 재할당할 크기
🤓 예제 : 런 타임에 크기가 결정된 배열의 크기를 realloc() 함수를 사용해 늘리기
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i, total_len;
int arr_len = 3, add_len = 2;
int* ptr_arr;
ptr_arr = (int*) malloc(arr_len * sizeof(int)); // 메모리의 동적 할당
if (ptr_arr == NULL) // 메모리의 동적 할당이 실패할 경우
{
printf("메모리의 동적 할당에 실패했습니다.\n");
exit(1);
}
printf("동적으로 할당받은 메모리의 초기값은 다음과 같습니다.\n");
for (i = 0; i < arr_len; i++)
{
printf("%d ", ptr_arr[i]);
}
total_len = arr_len + add_len;
ptr_arr = (int*) realloc(ptr_arr, (total_len * sizeof(int))); // 메모리의 추가 할당
if (ptr_arr == NULL) // 메모리의 추가 할당에 실패할 경우
{
printf("메모리의 추가 할당에 실패했습니다.\n");
exit(1);
}
printf("\n추가로 할당받은 메모리의 초기값은 다음과 같습니다.\n");
for (i = 0; i < total_len; i++)
{
printf("%d ", ptr_arr[i]);
}
free(ptr_arr); // 동적으로 할당된 메모리의 반환
return 0;
}
✨ 실행결과
동적으로 할당받은 메모리의 초기값은 다음과 같습니다.
0 0 0
추가로 할당받은 메모리의 초기값은 다음과 같습니다.
0 0 0 0 0
C. 스택 영역
1. 스택 프레임 (stack frame)
a. 스택 프레임의 정의
🌟 스택 영역에 차례대로 저장되는 함수의 호출 정보(함수의 매개변수, 호출이 끝난 뒤 돌아갈 반환 주소값, 함수에서 선언된 지역 변수 등)
스택 프레임 덕분에 함수의 호출이 모두 끝난 뒤에, 함수 호출 이전 상태로 돌아갈 수 있음
b. 스택 프레임의 동작 방식
🤓 기본 예제
int main(void)
{
func1(); // func1() 호출
return 0;
}
void func1()
{
func2(); // func2() 호출
}
void func2()
{
}
🎨 도식화
c. 스택 오버플로우 (stack overflow)
🌟 함수의 재귀 호출이 무한히 반복되어서 스택의 모든 공간을 다 차지하고 난 후 더 이상의 여유 공간이 없을 때 또 다시 스택 프레임을 저장하게 되면, 해당 데이터는 스택 영역을 넘어가서 저장되는 것
🎨 도식화
💥 스택 오버플로우가 되면 오동작을 하거나 취약점을 가지게 되므로 에러를 발생시키고 강제 종료 시킴
출처 : http://www.tcpschool.com/c/c_memory_structure
코딩교육 티씨피스쿨
4차산업혁명, 코딩교육, 소프트웨어교육, 코딩기초, SW코딩, 기초코딩부터 자바 파이썬 등
tcpschool.com
'프로그래밍 언어 > C' 카테고리의 다른 글
[문자와 문자열] 입출력 함수 총정리 2 : 문자열 (0) | 2023.08.17 |
---|---|
[문자와 문자열] 입출력 함수 총정리 1 : 스트림과 문자 (0) | 2023.08.17 |
[자료형(data type)] C 파생형 공용체와 열거체 (0) | 2023.08.17 |
[자료형(data type)] C 구조체 배열과 구조체 포인터, 구조체 활용 (0) | 2023.08.17 |
[자료형(data type)] C 파생형 구조체 기본 (0) | 2023.08.17 |