[C] realloc 함수

spring·2020년 11월 9일
0
    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

profile
Researcher & Developer @ NAVER Corp | Designer @ HONGIK Univ.

0개의 댓글