[C/C++] malloc과 new의 차이점 과 Stack Heap

티스토리 메뉴 펼치기 댓글수0

개발/C/C++/Objective C

[C/C++] malloc과 new의 차이점 과 Stack Heap

DrunkenPsycho
댓글수0

우리는 C와 C++에서 동적 할당을 위해 malloc 함수와 new 키워드를 자주 쓴다.

실제로 malloc과 new 모두 Heap 메모리에 저장 되는 경우가 많다. 하지만 Stack 메모리에 저장되는 경우도 있다.

오늘은 malloc과 new의 개요, 차이점과 Stack과 Heap의 개요와 차이점에 대해 알아보도록 하자.


1. malloc / free

   C에서는 동적 할당을 위해서 malloc함수와 free 함수를 자주 쓴다. malloc의 경우 함수로 stdlib.h 헤더파일에 포함되어 있다. malloc 함수를 사용하려면 "stdlib.h" 헤더를 반드시 포함해야 된다는 것이다. malloc 함수는 입력받은 바이트 크기 만큼 메모리 공간을 Heap Memory에 할당해준다. 예를 들면 다음과 같다.

 int *p; // 정수형 포인터 변수 p 선언

 p = (int *) malloc(sizeof(int)); // C에서의 int의 크기는 4 byte이므로 4 byte의 메모리 공간을 할당.

위에서 보다시피, malloc은 타입의 크기를 정확히 알고 써야 제대로 쓸 수 있다. char 형은 1 byte, double은 8byte다. 포인터 배열을 동적으로 할당 할 때도 마찬가지다. 배열의 크기 * 타입의 byte size 만큼의 크기로 해야된다. 그리고, malloc 함수의 타입이 void * 형이므로, 미리 각 타입에 맞게 캐스팅, 타입 변환을 해줘야 나중에 타입변환을 하지 않는 번거러움을 덜 수 있다. 또한 C에서는 Garbage Collector 가 없으므로, 사용자가 수동으로 동적 할당한 메모리를 수거 해야한다. 만약 malloc으로 메모리를 동적으로 받아 놓고 해제 해주지 않는다면, 메모리 누수 현상으로 인해 운영체제가 멈추는 경우도 발생한다. (이런 현상은 16비트 운영체제에서 빈번히 일어난다고 한다. 32비트 이상의 운영체제에서는  메모리 영역이 커지고, 메모리에 대한 관리 기법이 더 효과적으로 바뀌게 되어, 메가바이트 단위가 아니라면 이러한 일은 자주 발생 하지 않는다고 한다.) 이러한 현상을 방지하고자 할 때 쓰는 함수가 free다.

위에서 이어지게 쓴다면, 이렇게 될 것이다.

free(p);

free 또한 함수이고, 타입 또한 void * 형이다. 

C에서 프로그래밍을 했을 때, malloc을 사용했다면, free를 미리 써주고 다음 로직을 짜는 습관을 들이면 좋다. 

기본적인 프로그래밍 원칙인 할당을 해줬으면, 반드시 해제할 것. 꼭 숙지해 두도록 하자.

※Garbage Collector에 대해서는 다음에 더 자세하게 설명하도록 하겠다.


2. new / delete(~)

  C++에서는 동적할당에 대해 아예 키워드로써 제공해 준다. new 와 delete가 바로 그것이다. new 와 delete는 언어에서 기본으로 제공하는 "키워드"이기 때문에, 다른 헤더파일을 포함 시키거나 할 필요 없이 사용이 가능하다. new 키워드는 Heap 메모리에 할당해준다. 다음의 예제를 살펴보자.

int  *int_dynamic_alloc = new int(12345); // 정수형 포인터 변수에 new로 동적 메모리 할당

  C++에서 동적할당을 new로 선언 하려면 역시 포인터가 필요하다. new의 경우는 타입의 크기를 알아야 될 정도는 아니다. 이유로는 할당할 변수의 타입을 지정하면, 해당 타입의 포인터를 반환하게 된다. 즉, size 지정에 있어서 키워드를 사용하면 자동으로 사이즈가 결정되기 때문에 많이 편해졌다. (하지만 기본적으로 각 언어에서의 타입의 byte 크기는 필수 이므로 꼭 알아두도록 하자. 언제 유용하게 쓰일지 모른다.) 

또한, 클래스 객체를 동적 할당을 new로 하게 되면 생성자가 자동으로 호출된다. 비주얼 스튜디오에서 클래스를 만들게 되면 기본적으로 생성자와 소멸자를 같이 디폴트 형태로 만들어 준다. 여기에 생성자는 사용자 입맛대로 오버로딩(이름과 리턴타입은 같으나, 매개변수를 달리 하는 방법)으로 여러개의 생성자가 사용가능하다.

이렇게 new로 동적 할당을 해줬다면, 해제하는 키워드도 있기 마련이다. delete가 그것이다.

위의 예제에서  int_dynamic_alloc을 해제하고 싶다면, 아래와 같은 간단한 코드로 메모리 해제가 가능하다.

delete int_dynamic_alloc; // 메모리 할당 해제

C++에서도, 반드시 해제하는 습관을 들이도록 하자. Garbage Collector가 없는 이상, 할당 후 해제는 기본 옵션이라고 생각하자.


3. malloc / new 차이점

  C++에서는 기본적으로 malloc과 new 모두 사용이 가능하다. 그렇다면 차이점은 어떤 것이 있고, 어떠한 경우에 malloc이나 new를 선택하느냐를 알아보자.

  1) malloc은 기본적으로 라이브러리 제공 함수로, 함수 콜을 요청하게 된다. 하지만, new는 C++ 언어에서 제공하는 기본 키워드로, 별도의 라이브러리 추가없이 바로 사용이 가능하다.

  2) malloc은 기본적으로 사이즈를 매개변수로 받고, 리턴타입이 void *형이므로 sizeof 와 캐스트 연산자의 도움을 받아야 쉬운 코딩이 가능하다. 하지만 new는 할당할 타입을 지정하면, 알아서 할당할 타입의 포인터로 넘어오기 때문에, 할당할 타입과 같은 타입의 포인터 변수로 받아오기만 하면 끝이다.

  3) malloc은 메모리를 동적으로 할당하는 것만이 목적이므로 초기값을 지정해 줄 수 없지만, new의 경우는 할당과 동시에 초기화가 가능하다. 

  4) new 키워드는 생성자를 자동으로 호출하게 된다. 생성자는 객체를 자동으로 초기화 해주는 함수로, malloc과 new의 가장 큰 차이점이다. 

  차이점만 본다면, malloc은 없어도 new만 가지고도 쉽게 쉽게 코딩이 가능하다. 하지만 malloc이 필요한 경우 또한 분명히 존재한다. malloc의 경우에는 realloc이라는 함수로 재할당이 가능하지만, new에는 realloc에 대응하는 것이 없기 때문에, 새로 할당 -> 복사 -> 해제 하는 과정을 해야만 가능하다. 하지만, 할당 대상이 어디까지나 객체가 아니라는 전제하에서다. 객체는 반드시 new / delete 를 사용해야된다. 하지만 객체가 아니고, 재할당이 빈번하게 일어나야된다면, malloc과 free가 오히려 더 좋은 선택이 될 수도 있다.

  C에서는 동적 할당이 malloc 밖에 없지만, C++에서는 두가지 중 선택할 수 있으므로, 사용자의 입맛에 따라 어느 것을 사용해도 무방하다. 단, 할당 해제는 반드시 짝을 맞춰서 써야한다. new로 할당 했다면 delete로 해제하고, malloc으로 할당했다면 free로 해제해야만 한다.


4. Stack

  Stack은 자료구조에서 보자면, LIFO 구조의 자료형이다. 나중에 들어간 것이 먼저 나오게 된다. 가장 간단한 예로 들고다니면서 하나씩 빼서 쓸 수 있는 동전통이나, 하노이 탑이 있다.

  프로그램 상에서 Stack은 프로그램이 사용하는 메모리 영역으로, 임시적인 자료를 사용할 때나, 함수에서 자주 사용한다.(클래스를 new로 초기화 해주지 않았다면 이 또한 Stack 메모리로 들어간다.) 운영체제에 따라 차이가 있지만, Linux에서는 메모리상에서 높은 곳에서 점차 낮은 곳으로 쌓이고, Window에서는 메모리 상에서 가장 낮은 곳 부터 높은 곳으로 쌓이게 된다. 컴파일 될 때 스택의 크기가 결정이 되는 것이 대부분이다.


5. Heap

  Heap은 프로그램 상에서 사용자가 직접 할당하고 해제가 해야하는 영역으로, malloc함수, new 키워드로 동적 할당을 하게 되면 이 메모리를 사용하게 된다. heap은 Stack과는 정반대로 받는다. Stack이 맨 위에서 받는 구조면 Heap은 정반대 쪽부터 쌓이게 되고, 런타임 시에 메모리 크기 등이 결정된다.

  또한 Heap은 할당한 만큼 해제도 시켜줘야 한다.


6. Stack / Heap 차이점

  Stack과 힙은 기본적으로 사용자가 컨트롤 할지, 프로그램이 컨트롤 할지 와 컴파일시 되는지, 런타임시 되는지의 차이점이 있다. 또한 정적할당에 쓰이는 Stack은 상대적으로 작은 메모리 공간을 갖게 되고, 동적할당에 쓰이는 Heap은 상대적으로 큰 메모리 공간을 갖게된다.

우리가 보통 C와 C++에서는 Stack을 더 많이 쓰게 된다. main()도 그러하고, 그 안에 선언하는 변수들 모두 그러했다.

맨위로

https://drunkenpsycho.tistory.com/13

신고하기