void* realloc(void* ptr, size_t size);
realloc
함수는 malloc
, calloc
또는 realloc
으로 생성한 메모리블럭의 크기를 늘려주는 함수이다.
(realloc 의 첫번째 인수 ptr에 NULL을 주면 malloc 과 똑같이 동작한다.)
C의 엄청난 장점 중에 하나다.
예를들어 C 에서 vector
를 구현할때 realloc
을 사용하면 새로 할당한 배열에 기존 배열을 복사하는 비용을 절감할수 있다.
간단하게 벡터의 추가 연산에 대해 realloc
과 calloc
+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)로 써 시간차가 거의 나지 않는다.
천만개 이상이 되면 성능차이가 나기 시작하는데, 확연히 realloc
이 calloc
+ memcpy
보다 빠른걸 보여주고 있다. 약 5% 정도 빠르다.
중요한점은 realloc
을 쓰는것이 더 좋으냐? 라는 질문인데
답은 무조건 yes 이다.
우선 속도가 빠른이유는 당연하고, 위에 코드를 돌려보면 알겠지만 realloc
이 실패하면 calloc
+memcpy
방식 또한 실패한다.
즉 더 이상 할당할 방법이 없다는걸 의미한다.
이때부터는 다른 방법으로 해결해야지 할당의 문제로 여길것이 아니다.
심지어, 가상 주소 공간을 사용하는 현대 운영체제에서는 플랫폼(x86,x64) 에 따라 최대로 할당이 가능하기 때문에 주변 환경을 고려하지 않고 할당이 가능하다.
x86의 경우 힙에 대략 2GB 를 할당 할 수 있고, 큰 주소 공간 확장을 사용하면 4GB 까지 할당이 가능하다.
반면, x64 시스템은 이론상 2^63(약900경) 까지 할당이 가능하나, Windows OS 에서는 128GB 까지 할당이 가능하다.
심지어, 가상 메모리를 사용할 수 도 있으므로, x64 시스템에서는 거의 무제한으로 할당이 가능하다.
이제 realloc 이 실패하는 경우는 찾기가 힘들다.