본문 바로가기
SWE/C++ OOP

[C++][효율화] 공백 클래스의 크기는? / EBO란? / 최적화 기법 / 바이트 패딩

by S나라라2 2023. 5. 23.
반응형

 

공백 클래스의 사이즈?

Class Empty() {}

 예를 들어, 위와 같이 아무런 데이터가 없는 empty 클래스가 있다.

공백 클래스의 사이즈는 어떻게 될까?

 

정의된 데이터가 없으므로 객체는 메모리 사용을 하지 말아야한다고 생각할 있지만, 실제로 클래스의 사이즈는 1 나온다.

Std::cout << sizeof(Empty) << std::endl;  // 1

 

이유는, C++에서는 크기가 0 독립 구조의 객체가 생기는 것을 금지하기 때문이다. 따라서 비어있는 공백 객체에 char 개를 슬그머니 끼워 넣는 식으로 처리한다.

 

 

 

공백 클래스를 멤버변수로?

class Derived1 {
 private:
	int val;
	Empty em;
};

예를 들어, 공백 클래스를 멤버변수로 가지는 Derived1 클래스가 있다.

클래스의 사이즈는 어떻게 될까?

 

마찬가지로 클래스의 사이즈를 출력해보면, 공백 클래스에 메모리가 할당되는 것을 확인할 있다.

Sizeof(Derived1) > sizeof(int)

 

 

 

공백 기본 클래스 최적화 (Empty Base Optimization: EBO)

위의 예시에서 있듯이, 공백 클래스도 메모리를 할당하게 된다.

아무런 데이터를 저장하고 있지 않지만 의무적으로 할당되는 메모리를 절약하기 위해 사용하는 방법이 "공백기본클래스최적화 기법"이다.

'공백 기본 클래스 최적화' 구현 방법은 공백클래스를 데이터 멤버로 두지 말고, 상속하면 된다.

 

"EBO란, 공백 클래스를 상속관계의 기본 클래스로 사용될 때 발생하는 최적화 기법이다."

 

class Derived2 : private Empty {
 private:
	int x;
};

 

다음과 같이 Empty 공백 클래스를 상속받아서 구현할 경우, sizeof(Derived2) 크기는 멤버 데이터의 크기인 sizeof(int) 같게 된다!

주의할 사항은 EBO 기법은 단일 상속에서만 적용된다. 다중 상속 상속되는 클래스의 순서와 위치에 따라서 EBO 적용될 없는 경우도 있다.

 

 

 


[추가 학습] 바이트 패딩

 

Q. 아래 예제 코드에서, Derived1 클래스의 크기는 몇일까?

class Empty {};

class Derived1 {
    private:
        Empty em;
        int val;
};

std::cout << sizeof(Empty) << std::endl;   // 1
std::cout << sizeof(Derived1) << std::endl;

위의 예제를 출력해보면, 공백 클래스인 Empty 는 사이즈가 1인 것을 확인할 수 있다. 그러면 Derived1 클래스의 사이즈는 몇일까?

 

정답은 8이다.

 

멤버 변수로 있는 int val 을 위해 4bytes가 할당되고, Empty em를 위해 1bytes가 할당된다고 예측할 수 있지만, 틀렸다.

왜냐하면 C++ 컴파일러에서는 바이트 정렬을 위해 클래스에 바이트 패딩 과정을 추가하기 때문이다.

 

 

 

바이트 정렬(Byte Alignment)이란?

자료형의 크기와 메모리 상의 위치를 정렬하는 것을 말한다.

예를 들면, 정수형 변수는 4바이트 크기를 갖지만, CU는 8바이트씩 처리하므로 4바이트가 아닌 8바이트 단위로 정렬하여 메모리에 저장하는 것이 효율적이기 때문에 바이트 정렬이 필요하게 된다.

 

 

 

바이트 패딩(Byte Padding)이란?

바이트 정렬을 위해 추가될 수 있는 빈 공간을 말한다.

 

예를 들면, 4바이트 크기의 int형 3개와 1바이트 크기의 char 형 1개가 하나의 구조체로 정의되어 있다고 가정해보자

struct myStruct {
	int a;
    int b;
    int c;
    char d;
};

 메모리의 구성은 다음과 같다.

Memory layout:
	a[4] b[4] c[4] (padding bytes)[3] d[1]

4바이트 *3개 + 1바이트 *1개로 총 13바이트가 할당될 것 같지만,

C++ 컴파일러는 empty space를 3bytes할당함으로써 cpu 처리 단위인 4의 배수를 만들어낸다.

따라서 총 16바이트가 할당되게 된다.

 

참고: 32비트 시스템에서는 4bytes, 64비트 시스템에서는 8bytes로 구성하게 된다.

 

 

바이트 정렬과 바이트 패딩은 자료형의 크기와 메모리 상의 위치를 정렬하기 위해 사용된다. 이는 CPU의 메모리 접근 시간과 효율성을 개선하기 위한 것이다. 

 

 

 

 

 

바이트 패딩 연습 문제

Q. 공백 클래스 Empty가 존재하고, 해당 클래스를 멤버 변수로 가지고 있는 Derived1, Derived2, Derived3클래스의 크기를 맞춰보세요.

(힌트 : empty클래스의 크기는 1이고, 바이트 패딩과 바이트 정렬을 고려해보세요.)

class Empty {};

class Derived1 {
    private:
        Empty em;
        int val;
};

class Derived2 {
    private:
        Empty em;
        char val;
};

class Derived3 {
    private:
        Empty em;
        int val2;
        int val3;
        int val4;
        double val1;
};

int main() {
    std::cout << sizeof(Empty) << std::endl;   // 1
    std::cout << sizeof(Derived1) << std::endl;
    std::cout << sizeof(Derived2) << std::endl;
    std::cout << sizeof(Derived3) << std::endl;

    return 0;
}

 

 

정답

더보기

1 => 공백 클래스

8 => int[4] padding space[3] empty[1]

2 => char[1] empty[1]

24 => int[4] int[4] int[4] double[8] padding space[3] empty[1]

 

반응형