항목50 - new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 보자

Bogoomi·2022년 7월 24일
0

EffectiveC++

목록 보기
24/24

항목50 - new 및 delete를 언제 바꿔야 좋은 소리를 들을지를 파악해 보자



요약
프로그램을 짜다보면 오버런, 언더런과 같은 메모리 실수를 할 수도 있다. 이럴경우를 대비해
사용할 메모리의 앞 뒤에 경계표지(오버런/언더런 탐지용 바이트 패턴)을 넣어두어 만들 수 있고, 해당 경계표지 부분에 다른 정보가 적혀있다면
로그로 기록하여 문제를 일으킨 포인터 값을 알 수 있을 것이다.

경계표시 예시코드

static const int signature = 0xDEADBFFF;	//경계표시 내용



size_t realSize = size + 2 * sizeof (int);	// 경계표지 2개를 앞뒤에 붙일 수 있을 만큼 메모리 크기 늘려준다.

void *pMem = malloc(realSize);
if (!pMem) throw bad_alloc();

// 메모리 블록의 시작 및 끝부분에 경계표지를 기록
*(static_cast<int*>(pMem)) = signature;
*(reinterpret_cast<int*>(static_cast<Byte*>(pMem) + realSize- sizeof(int)) = signature;

// 앞쪽 경계표지 바로 다음의 메모리를 가리키는 포이터를 반환
return static_cast<Byte*>(pMem) + sizeof(int);

위 코드를 사용하였을 때, 문제점은 '바이트 정렬' 이다. 컴퓨터마다 특정 타입의 데이터가 특정 종류의 메모리 주소를 시작 주소로 하여 저장될 것을 요구함.
이를테면, 포인터는 4의 배수에 해당하는 주소에 마주어 저장되어야한다. 이러한 바이트 정렬 제약을 따르지 않는다면 프로그램이 실행되다가 하드웨어 예외를 일으킬 수 있다.
(최근 컴파일러의 성능이 좋아지면서 해당부분을 상세히 코드화할 필요는 없고 알고 있으면 좋다).

개발자가 자신의 프로그램이 동적 메모리를 어떤 성향으로 상용하는지를 제대로 이해하고 있다면, 기본 제공 버전을 썼을 때보다
사용자 정의 operator new와 operator delete를 사용할 때가 더 좋은 성능을 발휘할 수 있다.

언제 커스텀으로 new와 delete를 쓰면 좋을까?

  • 잘못된 힙 사용을 탐지하기 위해.
  • 동적 할당 메모리의 실제 사용에 관한 통계 정보를 수집하기 위해.
  • 할당 및 해제 속력을 높이기 위해(부스트의 pool 라이브러리)
  • 기본 메모리 관리자의 공간 오버헤드를 줄이기 위해(부스트의 pool 라이브러리)
  • 적당히 타협한 기본 할당자의 바이트 정렬 동작을 보장하기 위해
    x86 아키텍처에선 double이 8바이트 단위로 정렬되어 있을 때, 읽기,쓰기가 가장 빠르다. 하지만 operator new는 8바이트를 지원하지 않는다.
    이럴때 사용자 정의 버전으로 프로그램 성능을 끌어올릴 수 있다.
  • 임의의 관계를 맺고 있는 객체들을 한 군데에 나란히 모아 두기 위해
    페이지 부재 횟수를 최소화를 위해 해당 자료구조를 담을 별도의 힙을 생성하여 가능한 한 적은 페이지를 차지하도록 만들면 좋다.
    이러한 메모리 군집은 '위치 지정 new' 와 '위치 지정 delete' 를 사용하여 쉽게 구현 가능하다.
  • 그때그때 원하는 동작을 수행하도록 하기 위해
    공유메모리일 경우 메모리 할당과 해제를 API만을 이용해 할 수 있지만 사용자 정의 버전을 사용해도 가능하다.



잊지말자!

  • 개발자 스스로 정의하는 new 와 delete를 작성하는데는 여러 이유가 있음. 여기에서 수행 성능을 향상시키려는 목적, 힙 사용 시의 에러를 디버깅하려는 목적, 힙 사용 정보를 수집하려는 목적 등이 있음.
profile
개에에에바알

0개의 댓글