Memory API에는 여러가지가 있다.
여기서는 malloc(), sizeof(), free(), calloc(), realloc()을 볼 예정이다.
#include <stdlib.h>
void* malloc(size_t size)
→ heap에 메모리 공간을 할당한다.
→ malloc은 동적 할당. 아직 제대로 컴파일 전이므로 int형의 크기인 4가 출력된다.
#include <stdlib.h>
void free(void* ptr)
→ malloc에 의해 할당된 메모리 공간을 해제한다.
지역 변수로 선언하면 stack에 할당이 되는데
malloc을 사용하면 heap에서 할당이 되고 pi라는 것은 지역변수이므로 그대로 stack에 있지만 이 값이 포인터로 맨 위 할당된 주소 공간을 가리킨다.
freeing을 하면 다음과 같음.
char *src = "hello";
char *dst; // unaloocated
strcpy(dst, src); // segfault and die
src는 hello를 가르키고 있음. 메모리 할당이 되었음.
근데 dst는 할당이 안된 상태인데 dst로 src를 복사하려니까 오류가 난다.
올바른 코드는 다음과 같다.
char *src = "hello";
char *dst = (char*)malloc(strlen(src));
strcpy(dst, src);
사실 위의 코드도 잘한건 아님. strlen을 하면 5글자가 나오는데 사실 문자열은 \0값을 포함하여 총 6바이트인데 저만큼만 메모리 할당을 했으니 마지막 널값이 빠지게 된다. 물론 작동은 잘 함.
x에 할당은 했는데 값을 주지도 않고 바로 읽으려고함. 그러면 예전에 쓰여 있던 값, 즉 쓰레기값이 출력된다.
동적으로 메모리 할당 → 사용한 후에는 반환(free) 해줘야 한다.
그러나 오류로 인해 반환을 잊거나 할 수 없게되면,
그 메모리는 계속 사용되지 않으면서도 계속해서 시스템에 할당된 상태로 남게 된다.
프로그램의 실행 동안 지속적으로 발생할 수 있고, 시간이 지남에 따라 사용되지 않는 메모리가 계속 증가하게 되어 시스템의 전체적인 성능 저하를 초래하거나, 심한 경우에는 시스템이 사용할 수 있는 메모리가 부족해져 프로그램이나 시스템 전체가 비정상적으로 종료될 수 있다.
case 1: 메모리가 동적 할당된 후, 해당 메모리가 해제되었지만 포인터가 여전히 그 메모리 주소를 가리키고 있을 때
case 2: 지역 변수의 주소를 반환하는 함수에서, 함수가 종료된 후에 그 주소를 가리키는 포인터를 사용하려고 할 때
case 3: 이미 해제된 메모리 영역을 다시 해제하려고 할 때
→ Segmentation Fault 발생가능.
즉, 사용이 끝나기도 전에 메모리를 해제해서 사용하려고 하면 발생하는 것이다.
int *x = (int *)malloc(sizeof(int)); // allocated
free(x); // free memory
free(x); // free repeatedly
이미 free된 메모리를 다시 free하려고 하면 오류가 발생한다.
#include <stdlib.h>
void *calloc(size_t num, size_t size)
→ return하기 전에 값을 zero로 만들고 heap에 있는 메모리를 할당한다.
→ contiguous allocation의 줄임말. 메모리 내의 연속된 블록을 할당하는데 사용한다.
요청된 메모리의 크기를 초기화하여 0으로 설정한다.
→ malloc()은 초기화되지 않은 메모리를 반환함.
2개의 인자를 받는다. 할당할 요소의 수와 각 요소의 크기이다. 이 두 값의 곱으로 실제 할당될 메모리의 총량을 결정한다.
#include <stdlib.h>
void *realloc(void* ptr, size_t size)
→ memory block의 크기를 변경한다.
→ 즉, 이미 할당된 메모리 블럭의 크기를 변경하기 위해 사용된다.
→ 추가 메모리 영역을 할당하거나 메모리의 일부를 해제하여 사이즈를 조절할 수 있다.
#include <unistd.h>
int brk(void* addr)
void *sbrk(intptr_t increment);
프로그램의 데이터 세그먼트의 끝, 즉 break를 설정하거나 조회한다. 이 break는 heap의 끝을 나타낸다. argument로는 새로운 힙의 끝을 나타내는 포인터를 주고, 성공시 0, 실패시 -1을 반환한다.
brk를 사용하여 break를 증가하면 메모리는 프로그램에 할당되며, Break를 감소시키면 메모리는 프로그램에서 해제된다.
break를 주어진 값만큼 증가 또는 감소시킨다.
즉, 인자로 증가 또는 감소시키기 위한 바이트 수를 받고, 변경 전의 break 주소를 반환한다.
프로그래머는 절대 brk나 sbrk를 직접적으로 호출하지 않는다.
#include <sys/man.h>
void *mmap(void* ptr, size_t length, int prot, int flags, int fd, off_t offset)
mmap
은 메모리 매핑(memory mapping)을 수행하기 위한 시스템 콜이다.
파일 매핑
mmap
을 사용하면 파일을 메모리에 매핑하여 파일의 내용을 메모리 주소 공간에 직접 매핑할 수 있다 ⇒ 파일 입출력을 위해 일반적인 read
와 write
시스템 호출을 사용하는 것보다 훨씬 효율적으로 데이터에 액세스 할 수 있다.
익명 메모리 매핑
파일과 연관되지 않은 익명의 메모리 영역도 할당할 수 있다.
이는 동적 메모리 할당과 유사한 방법으로 사용될 수 있으며, 특정 경우에는 malloc 함수 내부에서 사용될 수도 있다.
메모리 공유
메모리 영역을 공유할 때 사용 가능하다.
Argument
Return