[운영체제] 9. Memory API

만두·2024년 1월 30일
0

운영체제

목록 보기
9/13

Memory API에는 여러가지가 있다.

여기서는 malloc(), sizeof(), free(), calloc(), realloc()을 볼 예정이다.


malloc()

#include <stdlib.h>

void* malloc(size_t size)

heap에 메모리 공간을 할당한다.

  • Argument
    • size_t size : 메모리 블록의 사이즈이다. 바이트단위
    • size_t는 unsigned integer type을 말한다.
  • Return
    - success : malloc에 의해 할당된 메모리 블럭의 void 형 포인터
    - fail : null 포인터

sizeof()

  • routine, macro는 숫자를 직접 입력하는 대신 malloc에서 크기를 위해 사용된다.
  • 변수에 대한 sizeof의 결과는 두가지 종류가 있다.
    - 실제 사이즈 x를 run-time(실행 시간)에 알게되는 경우

→ malloc은 동적 할당. 아직 제대로 컴파일 전이므로 int형의 크기인 4가 출력된다.

  • 실제 사이즈 x를 compile-time(컴파일 시간)에 알게되는 경우

free()

#include <stdlib.h>

void free(void* ptr)

→ malloc에 의해 할당된 메모리 공간을 해제한다.

  • Argument
    • void * ptr : malloc에 의해 할당된 메모리 블럭을 가리키는 포인터
  • Return
    • none

지역 변수로 선언하면 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바이트인데 저만큼만 메모리 할당을 했으니 마지막 널값이 빠지게 된다. 물론 작동은 잘 함.


# 만약, 초기화를 잊었다면? ![](https://velog.velcdn.com/images/eunseo120/post/eb104fd7-46b8-4d83-aae6-be26c66b7c6c/image.png)

x에 할당은 했는데 값을 주지도 않고 바로 읽으려고함. 그러면 예전에 쓰여 있던 값, 즉 쓰레기값이 출력된다.

Memory Leak 메모리 누수

  • 프로그램이 메모리를 벗어나서 결국에는 죽는것.
  • unused된 것은 말그대로 사용되지 않는것이지 해제된 것은 아니다.
  • 프로그램이 할당된 메모리를 올바르게 반환하지 않는 경우를 말한다.

동적으로 메모리 할당 → 사용한 후에는 반환(free) 해줘야 한다.

그러나 오류로 인해 반환을 잊거나 할 수 없게되면,

그 메모리는 계속 사용되지 않으면서도 계속해서 시스템에 할당된 상태로 남게 된다.

프로그램의 실행 동안 지속적으로 발생할 수 있고, 시간이 지남에 따라 사용되지 않는 메모리가 계속 증가하게 되어 시스템의 전체적인 성능 저하를 초래하거나, 심한 경우에는 시스템이 사용할 수 있는 메모리가 부족해져 프로그램이나 시스템 전체가 비정상적으로 종료될 수 있다.


# Dangling Pointer 💡 **댕글링 포인터(Dangling Pointer)** : 메모리를 가리키던 포인터가 해당 메모리 영역을 더이상 참조하지 않아야 할 때, 그 메모리 영역이 반환되거나 할당 해제되었음에도 불구하고 여전히 그 주소를 가리키고 있는 포인터

case 1: 메모리가 동적 할당된 후, 해당 메모리가 해제되었지만 포인터가 여전히 그 메모리 주소를 가리키고 있을 때

case 2: 지역 변수의 주소를 반환하는 함수에서, 함수가 종료된 후에 그 주소를 가리키는 포인터를 사용하려고 할 때

case 3: 이미 해제된 메모리 영역을 다시 해제하려고 할 때

Segmentation Fault 발생가능.

즉, 사용이 끝나기도 전에 메모리를 해제해서 사용하려고 하면 발생하는 것이다.


# Double Free
int *x = (int *)malloc(sizeof(int)); // allocated
free(x); // free memory
free(x); // free repeatedly

이미 free된 메모리를 다시 free하려고 하면 오류가 발생한다.

calloc()

#include <stdlib.h>

void *calloc(size_t num, size_t size)

→ return하기 전에 값을 zero로 만들고 heap에 있는 메모리를 할당한다.

→ contiguous allocation의 줄임말. 메모리 내의 연속된 블록을 할당하는데 사용한다.

  1. 요청된 메모리의 크기를 초기화하여 0으로 설정한다.

    → malloc()은 초기화되지 않은 메모리를 반환함.

  2. 2개의 인자를 받는다. 할당할 요소의 수와 각 요소의 크기이다. 이 두 값의 곱으로 실제 할당될 메모리의 총량을 결정한다.

  • Argument
    • size_t num: 할당할 블럭의 수
    • size_t size:각 블럭의 크기(바이트 단위)
  • Return
    - success : calloc에 의해 할당된 메모리 블럭을 가르키는 void형 포인터
    - fail : null 포인터

realloc()

#include <stdlib.h>

void *realloc(void* ptr, size_t size)

→ memory block의 크기를 변경한다.

→ 즉, 이미 할당된 메모리 블럭의 크기를 변경하기 위해 사용된다.

→ 추가 메모리 영역을 할당하거나 메모리의 일부를 해제하여 사이즈를 조절할 수 있다.

  • realloc에 의해 반환되는 포인터는 ptr과 같거나 새로운 것일지도 모른다.
  • Argument
    • void *ptr : malloc, calloc, realloc 등에 의해 할당된 메모리 블럭을 가르키는 포인터
    • size_t size : 메모리 블럭의 새로운 사이즈(바이트 단위)
  • Return
    • success : 메모리 블럭의 void 형 포인터
    • fail : null 포인터

# System calls
#include <unistd.h>

int brk(void* addr)
void *sbrk(intptr_t increment);
  • malloc 라이브러리 콜은 brk 라는 시스템 콜을 사용한다.
  • brk, sbrk는 프로세스의 heap 영역의 끝을 제어하기 위한 시스템콜이다.
  • 참고로 heap은 동적으로 할당되거나 해제되는 메모리를 관리하는 영역이다.

brk()

프로그램의 데이터 세그먼트의 끝, 즉 break를 설정하거나 조회한다. 이 break는 heap의 끝을 나타낸다. argument로는 새로운 힙의 끝을 나타내는 포인터를 주고, 성공시 0, 실패시 -1을 반환한다.

brk를 사용하여 break를 증가하면 메모리는 프로그램에 할당되며, Break를 감소시키면 메모리는 프로그램에서 해제된다.

sbrk()

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()

mmap은 메모리 매핑(memory mapping)을 수행하기 위한 시스템 콜이다.

  1. 파일 매핑

    mmap을 사용하면 파일을 메모리에 매핑하여 파일의 내용을 메모리 주소 공간에 직접 매핑할 수 있다 ⇒ 파일 입출력을 위해 일반적인 readwrite 시스템 호출을 사용하는 것보다 훨씬 효율적으로 데이터에 액세스 할 수 있다.

  2. 익명 메모리 매핑

    파일과 연관되지 않은 익명의 메모리 영역도 할당할 수 있다.

    이는 동적 메모리 할당과 유사한 방법으로 사용될 수 있으며, 특정 경우에는 malloc 함수 내부에서 사용될 수도 있다.

  3. 메모리 공유

    메모리 영역을 공유할 때 사용 가능하다.

  • Argument

    • ptr : 원하는 매핑의 시작 주소. 일반적으로 NULL로 설정되어 운영체제가 주소를 결정하도록 한다.
    • length : 매핑할 메모리의 크기
    • prot : 메모리 영역의 보호 속성 (ex. PROT_READ, PROT_WRITE)
    • flags : 매핑의 특성과 타입을 지정하는 플래그 (ex. MAP_SHARED, MAP_PRIVATE, MAP_ANONYMOUS)
    • fd : 매핑할 파일의 파일 디스크립터. 익명 메모리를 매핑하는 경우 -1로 설정
    • offset : 파일 내에서 매핑을 시작할 위치
  • Return

    • success : 매핑된 메모리 영역의 시작 주소
    • fail : -1
profile
아무것도 모르는 말하는 감자 입니다

0개의 댓글

관련 채용 정보