[C] realloc 함수

void* realloc(void* ptr, size_t size);

realloc 함수는 malloc , calloc 또는 realloc 으로 생성한 메모리블럭의 크기를 늘려주는 함수이다.

(realloc 의 첫번째 인수 ptr에 NULL을 주면 malloc 과 똑같이 동작한다.)

C의 엄청난 장점 중에 하나다.

예를들어 C 에서 vector 를 구현할때 realloc 을 사용하면 새로 할당한 배열에 기존 배열을 복사하는 비용을 절감할수 있다.

간단하게 벡터의 추가 연산에 대해 realloccalloc+memcpy의 성능을 측정해보자

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<time.h>
typedef struct VEC {
	int* base;
	int sz, cp;
}VEC;
void push_back_realloc(VEC* _this, int value) {
	if (_this->sz == _this->cp) {
		int* temp = _this->base;
		_this->base = (int*)realloc(_this->base, (_this->cp = _this->cp ? _this->cp << 1 : 1) * sizeof(int));
		if (_this->base==NULL) {
			puts("Realloc Failure");
			int* tmp = (int*)malloc(_this->cp * sizeof(int));
			if (tmp == NULL) {
				puts("Also failure");
				system("pause");
				exit(1);
			}
			memcpy(tmp, _this->base, _this->sz * sizeof(int));
			free(_this->base);
			_this->base = tmp;
		}
	}
	_this->base[_this->sz++] = value;
}
void push_back_calloc_memcpy(VEC* _this, int value) {
	if (_this->sz == _this->cp) {
		int* temp = (int*)calloc(_this->cp = _this->cp ? _this->cp << 1 : 1, sizeof(int));
		if (temp == NULL) {
			puts("calloc Failure");
			system("pause");
			exit(1);
		}
		memcpy(temp, _this->base, _this->sz * sizeof(int));
		free(_this->base);
		_this->base = temp;
	}
	_this->base[_this->sz++] = value;
}
#define N 10000000
int main() {
	int T = 100;
	while (T--) {
		double beg = clock();
		VEC a = { 0 };
		for (int i = 0; i < N; i++) {
			push_back_realloc(&a, i);
		}
		printf("realloc time : %f\n", (clock() - beg) / CLOCKS_PER_SEC);
		beg = clock();
		VEC b = { 0 };
		for (int i = 0; i < N; i++) {
			push_back_calloc_memcpy(&b, i);
		}
		printf("malloc time : %f\n", (clock() - beg) / CLOCKS_PER_SEC);
		//free(a.base);
		//free(b.base);
	}
	system("pause");
}

이 코드로 부터, 각각의 방식에 대한 성능과 realloc이 실패하는 시점을 알아볼 것이다.

.
.
.
realloc time : 0.321000
malloc time : 0.381000
realloc time : 0.319000
malloc time : 0.353000
realloc time : 0.365000
malloc time : 0.361000

데이터가 작을때는 벡터의 추가연산이야 뭐 O(1)로 써 시간차가 거의 나지 않는다.

천만개 이상이 되면 성능차이가 나기 시작하는데, 확연히 realloccalloc + memcpy 보다 빠른걸 보여주고 있다. 약 5% 정도 빠르다.

중요한점은 realloc 을 쓰는것이 더 좋으냐? 라는 질문인데

답은 무조건 yes 이다.

우선 속도가 빠른이유는 당연하고, 위에 코드를 돌려보면 알겠지만 realloc 이 실패하면 calloc+memcpy 방식 또한 실패한다.

즉 더 이상 할당할 방법이 없다는걸 의미한다.

이때부터는 다른 방법으로 해결해야지 할당의 문제로 여길것이 아니다.

심지어, 가상 주소 공간을 사용하는 현대 운영체제에서는 플랫폼(x86,x64) 에 따라 최대로 할당이 가능하기 때문에 주변 환경을 고려하지 않고 할당이 가능하다.

x86의 경우 힙에 대략 2GB 를 할당 할 수 있고, 큰 주소 공간 확장을 사용하면 4GB 까지 할당이 가능하다.

반면, x64 시스템은 이론상 2^63(약900경) 까지 할당이 가능하나, Windows OS 에서는 128GB 까지 할당이 가능하다.

심지어, 가상 메모리를 사용할 수 도 있으므로, x64 시스템에서는 거의 무제한으로 할당이 가능하다.

이제 realloc 이 실패하는 경우는 찾기가 힘들다.

References