메모리 동적 할당을 해보자
C/C++에서는 동적할당을 통해 개발자가 원하는 만큼 메모리를 할당할 수 있습니다.
다음과 같이 말이죠.
//pA, pB는 char 형의 포인터
char* pA;
char* pB;
//pA와 pB를 이용해 메모리 동적할당. 뒤에 있는 1은 할당 크기이며, 1바이트를 나타냄
pA = (char*)malloc(1);
pB = (char*)malloc(1);
//동적할당했던 pA, pB를 할당해제시켜준다
free(pA);
free(pB);
메모리를 지우면서 생긴 의문
포인터로 동적할당한 메모리는 delete 혹은 free 함수를 통해 반납하게 되는데요, delete()나 free()에는 포인터만 있고 사이즈와 관련된 파라미터가 들어가지 않습니다. 분명 정해진 만큼의 크기만 메모리를 지워줘야 하는데도요. "메모리를 OO만큼 지워라" 라고 명령을 해야하는데, 그냥 "메모리를 지워라" 라고만 하고 있습니다. 동적할당했던 영역과 다르게 메모리를 지운다면 엉뚱한 데이터까지 할당해제 하거나, 영원히 할당해제되지 않는 메모리가 생길 겁니다.
동적 할당 오버헤드를 찾다
저는 이런 메모리에 대한 정보가 오버헤드로써 저장되는 곳이 반드시 있을거라 생각했습니다. "동적 할당 오버헤드", "malloc 오버헤드" 등의 키워드로 검색해보니, 확실히 메모리 사이즈에 대한 오버헤드를 따로 저장하고 있는 것을 알게 됐습니다. 다음과 같이 말이죠.
그림과 같이 size, prev_size 외 몇몇 변수들이 오버헤드로 사용된 것을 볼 수 있습니다. 사실 사이즈만 오버헤드인 것이 아니었죠. 메모리 할당이 연속된 메모리상에서 될 수도 있지만, 때로는 다른 메모리 블록으로 건너가 데이터에 접근해야할 수도 있습니다. 그럼 다음 블록을 가리키는 포인터가 또 오버헤드로 사용될겁니다. 이렇듯 메모리 동적할당에는 추가적으로 메모리 투자를 해줘야됩니다.
동적할당 오버헤드가 얼마일까?
저는 이 오버헤드가 얼마나 되는지를 알고 싶었습니다. 일하다가 자료구조에 여러 개의 변수를 동적 할당할 일이 있었거든요. 동적할당 오버헤드의 크기는 컴파일러, 운영체제, 하드웨어 등 조건에 따라 달라지기 때문에 명확한 답을 주는 곳이 없었습니다. 다행히 코드를 통해 동적 할당 오버헤드를 계산할 수 있었습니다.
실험에 사용한 코드는 다음과 같습니다.
int main()
{
ptrdiff_t diff = 100;
for (int i = 0; i < 100; i++) {
char* a, * b;
//a = (char*)malloc(1);
//b = (char*)malloc(1);;
a = new char(1);
b = new char(1);
cout << "tried : " << i + 1 << " times" << " diff=" << abs(diff) << endl;
if (abs(diff) > abs(a - b)) {
diff = a - b;
}
}
}
char 한 개의 크기는 1바이트입니다. 그런데, 1바이트 짜리 char을 계속 동적할당하고, 이 char 포인터들의 간격을 재보면 어떨까요? 그 간격 안에는 char 원본 데이터와, 오버헤드 데이터가 담겨있을 겁니다.
코드의 실행 결과는 다음과 같습니다.(주의 : 비주얼 스튜디오는 릴리즈 모드로 실행할 것)
- 실험 조건 : 64비트, Win10
주소 간격이 16, 7408, 176 등 다양하게 나오네요. 동적 할당이 될 때마다 바로 옆에 있는 자리를 내줄 수도 있지만, 자리가 없으면 꽤 먼 곳에도 할당을 해주는 것을 알 수 있습니다. 가장 작은 크기가 16바이트로 나오는군요. 거의 다 왔습니다.
그래서 몇인데
최종적으로 오버헤드를 8바이트로 계산했습니다.
- 16바이트 중에서 8바이트는 원본 char 데이터를 위한 자리입니다. 64비트 운영체제로 실험한 거라서 8바이트 단위로 메모리가 정렬(align)되거든요. (이건 나중에 한 번 더 다루면 좋을 것 같습니다)
- 8바이트 오버헤드는, 일단 size를 위한 4바이트 자리를 갖습니다. 거기에, 메모리 관련 부울 변수들을 맨 끝자리에 3개 가집니다.
8바이트 오버헤드 속에 free 함수에서 사용할 size를 가지고 있었네요. 이것 저것 해본 끝에 제가 궁금하던 걸 찾을 수 있어서 좋은 시간이었습니다. (CTO가 숙제로 내주셨던 건 비밀)
참고자료
'개발이야기' 카테고리의 다른 글
Cognito 에서 Nickname 중복 체크하기 (0) | 2019.07.13 |
---|---|
7개월차 개발자의 이야기 (0) | 2019.07.13 |
[MySQL] EXPLAIN 으로 쿼리문 테스트 하기 (0) | 2019.07.13 |
Zbar , OpenCV 사용해서 QR코드 인식하기 (0) | 2019.07.12 |
디자이너가 없는 회사에서 디자인 작업을 하는 방법. (0) | 2019.07.12 |