전공/운영체제
14. Memory API
nongdamgom
2024. 1. 4. 21:35
Memory API : malloc()
#include <stdlib.h>
void *malloc(size_t size)
- size_t size => memory block sizke (byte)
- size => unsigned integer type
- void type pointer로 시작 주소가 return 됨
- 할당 실패 시 null pointer 반환
sizeof()
int *x = malloc(10 * sizeof(int));
printf("%d\n", sizeof(x));
/* malloc에 할당 되는 byte는 runtime에 잡히지만
sizeof() 자체는 macro라서 compile time에 수행 됨(포인터가 가리키는 곳 크기를 모름)
즉, 그냥 포인터 변수의 크기인 4가 출력된다. */
int x[10];
printf("%d\n", sizeof(x));
/* 정적 배열은 compile time에 크기가 할당되므로,
sizeof가 compile time에 크기를 알 수 있음, 즉 int 배열 크기인 40이 출력 됨 */
Memory API : free()
#include<stdlib.h>
void free(void* ptr) // 할당한 공간의 시작 주소를 넘긴다
- 시작 주소만 알고 전체 공간을 할당 해제 할 수 있는 이유?
- => 할당 할 때부터, 추가 8~16byte 정도 더 할당해서, 여기에 크기 정보를 기록해 놓음
Memory Allocating & freeing
int *pi;
pi = (int *)malloc(4 * sizeof(int));
free(pi);
- free 한다고 해서, pi 변수 내의 저장된 값(free한 공간의 시작 주소값)이 지워지는건 아님.
- 나중에 이 변수로 뭔가를 하려고 하면 에러 날 수 있다.
Forgetting To Allocate Memory
char *src = "hello";
char *dst;
strcpy(dst, src);
- strcpy를 하면 scr에 있는 내용을 dst에 카피 하게 됨.
- 정적으로 char*를 바로 잡아서 hello는 hello\0로 code section에 들어가게 됨.
- dst는 초기화를 해주지 않아서, 쓰레기 값이 들어가게 되는데, 그러면 카피를 할 때, OS에게 허가 받지 않은 공간에 hello를 할당 해 버릴 수가 있음 => segmentation fault
Solution
char *src = "hello";
char *dst = (char *)malloc(strlen(src) + 1);
strcpy(dst, src);
- dst를 미리 malloc 으로 초기화 해주면, 공간 허가를 받은 곳에 strcpy를 진행하므로 에러가 없다.
- strlen은 null을 제외하고 복사하므로, malloc시 +1을 해줘야 nullptr 공간을 확보할 수 있다.
Not Allocating Enough Memory
char *src = "hello";
char *dst = (char *) malloc(strlen(src));
strcpy(dst, src);
- 만약 nullptr 공간을 확보하지 않은채 strcpy를 하면 어떻게 될까?
- Incorrect code 이지만, 돌아가는데는 문제가 없다.
- strcpy는 무조건 null이 나올 때까지 copy를 한다.
- 이 때, 위에서 말 했듯이, malloc이 넉넉하게 공간을 할당하기 때문에 null 공간을 확보하지 않아도 잘 돌아간다.
Forgetting to Initialize
int *x = (int *) malloc(sizeof(int));
printf("*x = %d\n", *x);
- 첫 줄로 x에 공간의 크기는 할당하였지만, 정작 그 할당한 공간의 내용은 초기화 되지 못함
- 공간 내의 값이 쓰레기 값으로 채워지게 됨 .
int *x = (int *) malloc(sizeof(int));
memset(x, 0, sizeof(int));
printf("*x = %d\n", *x);
- memset을 이용하여 초기화를 해주면 해결이 가능하다.
- memset(초기화 할 곳의 포인터, 초기화 할 값, 그 공간의 사이즈)
- memset은 <string.h>에 있다.
Memory Leak
- 할당 받은 공간을 사용하지 않는다면 free를 꼭 해줘야 memory leak을 막을 수 있다.
- free()하지 않는다면, memory 공간이 꽉 차서 run out of memory 에러가 날 수 있음.
Dangling pointer
- 어떤 pointer가 이미 free 된 공간을 가리키고 있을 때 dangling pointer 라고 함.
- list에서 중간 node를 해제한다면, tmp node를 하나 만들어서 앞뒤로 연결을 해준 후 free 해줘야 한다.
Other Memory APIs : calloc()
#include <stdio.h>
void *calloc(size_t num, size_t size)
/* 예시 */
malloc(10 * sizeonf(int))
calloc(10, sizeof(int))
// 둘은 같음
- size_t num : number of blocks to allocate
- size_t size : size of each block(in byte)
- malloc과 다르게 초기화를 자동으로 0으로 해준다
- => 자동 0 초기화 때문에 느림, mallock + memset이 성능이 더 좋다.
Double Free
int *x = (int *)malloc(sizeof(int));
free(x);
free(x); // undefined error
/* solution */
free(x);
x = NULL; // (void *) 0 를 가짐
/* 나중에 free 하고 싶을 때 */
if(x != NULL)
free(x); // 한번 더 확인 할 수 있음
System Calls
#include <unistd.h>
int brk(void *addr);
void *sbrk(intptr_t increment);
- malloc 이 heap 공간을 더 할당 받고 싶을 때 brk 라는 system call을 사용하여 OS에 요청
- heap의 끝부분을 break라고 부름
- brk : 새로운 break의 절대 주소를 인자로 받음
- sbrk : 새로운 break와 이전의 차이 값을 인자로 받음
=> 프로그램은 brk나 sbrk를 절대로 directly call 할 수 없다. (malloc에 의해 자동 호출)