본문으로 바로가기

OOP의 이해 - ② Object Alignment

category Computer Science/C++ 2021. 10. 12. 16:28

Object Alignment

class 혹은 struct의 오브젝트가 메모리에 저장될 때 규칙을 알아본다. 아래의 클래스를 보자.

class cat{
public:
    cat();
private:
    int ia;    // 4 바이트
    int ib;    // 4 바이트
    double dc; // 8 바이트
};

이 클래스의 오브젝트의 크기를 출력해보면 16이 나온다. 그리고 아래의 class를 보자.

class Cat{
public:
    void Speak();
private:
    int ia;    // 4 바이트
    double dc; // 8 바이트
    int ib;    // 4 바이트
};

이 클래스의 오브젝트의 크기를 출력해보면 24가 나온다. 멤버 변수 크기의 합은 같지만, 저장되는 크기는 다른 이유는 오브젝트가 메모리에 저장될 때 두 가지의 규칙이 있기 때문이다.

  • 멤버 변수는 자신의 크기의 배수에 해당하는 위치에서만 시작할 수 있다.
  • 오브젝트의 전체 크기는 가장 큰 변수 크기의 배수여야 한다.

이 규칙에 따라 아래와 같은 클래스의 오브젝트의 크기를 계산해 보자.

class Cat{
public:
    void Speak();
private:
    char ca;   // 1 바이트
    int ib;    // 4 바이트
    int ic;    // 4 바이트
    double dd; // 8 바이트
};

위 오브젝트의 크기는 1 + (3) + 4 + 4 + (4) + 8 총 24 바이트가 된다. (괄호로 표시된 크기가 패딩 값)

class alignas

class가 메모리에 저장되는 크기를 alignas 키워드로 지정할 수 있다. 이는 병렬 프로그래밍에서 필요하다. 고속 병렬 프로그래밍에서는 cpu는 각 코어에 있는 cache line을 단위로 메모리에 액세스 하게 된다. cache line의 크기는 일반적으로 64바이트를 가진다. 그런데 만약 24바이트 크기의 클래스가 배열에 저장되어 있고 이 배열을 병렬적으로 접근한다면 하나의 객체가 서로 다른 코어에 저장되는 false sharing 문제가 발생할 수 있다. 이런 경우를 대비하여 다음과 같이 class의 크기를 지정할 수 있다.

#include <iostream>
class alignas(32) Cat{
public:
    void Speak();
private:
    char ch[24]; // 24바이트
};
int main()
{
    Cat stackCat;
    std::cout << sizeof(stackCat) << std::endl;
    return 0;
}

alignas(32)로 지정할 경우 해당 클래스의 크기를 32의 배수로 설정하게 된다. 따라서 위 코드의 출력 결과는 32가 된다.

 


출처: https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg