본문 바로가기
프로그래밍/컴퓨터 과학(CS)

C++ 클래스와 구조체의 데이터 정렬(Data alignment) 왜 데이터 크기가 다르지?

by Hwan2 2020. 6. 24.
반응형

우리는 C++를 사용할 때 class나 struct를 사용합니다.


알고계시는 분들도 있겠지만 기본적으로 맴버변수를 선언하면 자료형의 크기가 맞춰집니다.


이를 컴파일 데이터 정렬이라고 하는데, 일단 코드를 보시죠.


#include <iostream>

class A {
    int num;    //4byte
    char c1;     //1byte
    char c2;    //1byte
};

int main(void) {
    printf("%d\n"sizeof(A));
    return 0;
}


6바이트가 나와야 하지만 8바이트가 나오게 됩니다. 이는 구조체(struct)도 마찬가지 입니다.


왜 이렇게 되는지 살펴보고자 합니다.



1. 프로세스의 메모리 접근 단위

기본적으로 해당 코드를 실행하면 메모리로 올라가게 됩니다.
그리고 프로세스는 함수가 실행될 때마다 변수의 주소값을 통해 메모리로 접근해 원하는 정보를 가져오게 되죠.

char[10] 이라는 배열이 있다고 했을 때, 프로세스는 해당 자료를 어떻게 접근하게 될까요?


프로세스는 1바이트씩 접근해서 해당 변수를 가져오게 될까요?

처음 파랑색 접근, 두번째는 주황색 접근, 세번째는 회색 접근......

이런식의 비효율적인 접근은 하지 않습니다.


프로세스는 데이터에 접근할 때 최소 2바이트 단위로 접근하게 되죠.

2, 4, 8, 16, 32바이트까지 한번에 가져와 처리하게 됩니다.

보통은 1word 단위(4byte)로 가져오게 됩니다.



이런식으로 말이죠....

그럼 데이터가 정렬되지 않았을 때 어떻게 처리되는지 보겠습니다.

2. 데이터가 정렬되지 않았을 때(No Data alignment)



이렇게 들어있다고 가정해보겠습니다.

int num1과 char c1, c2접근은 무리없이 접근하지만, 문제는 num2입니다.


일반적으로 주소값에 접근할 때 시작 주소로부터 2바이트 혹은 4바이트 단위로 읽어온다고 했습니다.

해당 예시에선 4바이트 단위로 읽어오게 되죠.

즉, 컴파일러는 6의 위치부터 읽어오는게 아닌 8부터 읽어오게 됩니다.


이는 int 때문인데, 자료형이 큰 순서로 데이터를 읽어오게 됩니다.(저기에 double이 있다면 8바이트씩 읽어오게 됩니다.)

그럼 프로세스는 잘린 num2를 받게되고 다시 메모리에 접근하게 됩니다.


이런식으로 되버립니다.

데이터 양이 많을수록 1번 처리할 껄 2번 처리하기 때문에 성능저하게 나타나게 됩니다.


이런 현상을 해결하고자 데이터 자료형을 갖고있는 class(struct)의 데이터들(맴버 변수들)중 가장 큰 데이터의 값을 기준으로

Padding시켜주게 됩니다.


3. 데이터가 정렬되었을 때(Data alignment)


이렇게 말이죠....

때문에 위 예제에서의 8바이트는 int자료형에 맞춰 남은 부분을 padding으로 채워넣어 8바이트가 잡히게 되는 것입니다.


또한 class가 연속으로 선언된 경우 class마다 간격을 두고 메모리할당을 하게 됩니다.


#include <iostream>

class A {
    int num;
    char c;
    char c1;
public:
    void print() {
        printf("A = %X\n"this);
    }
};

class B {
    int num;
    char c;
    char c1;
public:
    void print() {
        printf("B = %X\n"this);
    }
};

class C {
    int num;
    char c;
    char c1;
public:
    void print() {
        printf("C= %X\n"this);
    }
};

int main(void) {
    A a; a.print();
    B b; b.print();
    C c; c.print();
    return 0;
}


Visual Studio 2019기준 10 ~ 12바이트씩 떨어져서 할당되게 됩니다.(여러번 실행해보면 조금씩 차이가 납니다.)

이렇게 함으로써 데이터가 잘리고, 충돌되는 일은 없게되는 것이죠


단, 싱글코어나 하나의 쓰래드로 데이터를 처리할 때는 상관 없지만

멀티코어 + 멀티 쓰래드로 클래스에 접근하여 데이터를 처리하게 되면 문제가 발생할 수 있습니다.

false sharing문제인데요. 이것에 관해서는 https://hwan-shell.tistory.com/230?category=703822 이 글을 참고하시길 바랍니다.



참고 레퍼런스 : 

https://developer.ibm.com/technologies/systems/articles/pa-dalign/

https://www.kdata.or.kr/info/info_04_view.html?field=&keyword=&type=techreport&page=31&dbnum=178628&mode=detail&type=techreport


반응형

댓글


스킨편집 -> html 편집에서