본문 바로가기
C++ 200제/코딩 IT 정보

[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields 프로그래밍 성능 관리)

by vicddory 2017. 9. 30.

[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields 프로그래밍 성능 관리)


메모리 사용 최적화(Optimizing Memory Usage)


C++ 강좌, 메모리 최적화 장점

- 더 빠른 실행속도

- 시스템 자원들의 효율적 사용

- 메모리 최소 사용


코드 최적화 위의 모든 것을 향상하려 노력한다. 그리고 C++에서 선언 재할당 기법은 불필요한 객체 생성과 해제를 제거하여 프로그램 크기를 줄이고 실행시간 속도를 향상한다.


그러나 다른 최적화 기법들은 하나의 방향(더 빠른 코드 또는 더 작은 메모리 점유)으로 심하게 치우친다. 때론, 최적화 목표들은 상호 배타적이기도 하다. 즉, 메모리 점유를 작게 만드는 것은 더 느린 코드를 초래하며 반면에 더 빠른 코드는 더 큰 메모리 점유로 이어진다. 이 포스팅에선 메모리 요구를 줄이거나 코드를 소형화하는 기법을 설명한다.

C++ 강좌[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields)

Bit Fields


C와 C++ 모두 작은 데이터를 직접 저장하고 액세스할 수 있다.


단일 비트. 하나의 비트가 C/C++ 구현을 위한 자연적인 저장장소 단위가 아니다.

bit fields의 사용은 하나 이상 비트들의 시퀀스를 액세스하는 것에서 프로세서에 의해 발휘되는 추가적인 조치들 때문에 실행 파일의 크기를 증가시킬 수 있다.


메모리 사용을 최소화하기 위하여 실행시간 속도를 희생하는 명쾌한 예이다.


C++ 메모리 최적화[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields)


보통 겨우 몇 바이트 아끼자고 비트 필드들을 사용하지 않는다. 그러나 어떤 애플리케이션들을 위하여 실행속도와 저장장소의 간결화 사이의 절충은 필요하다.


예를 들면 평균적인 국제전화 회사의 청구서 시스템(billing system)은 모든 전화통화를 관계형 데이터베이스 속에 하나의 레코드로 저장한다. 이 레코드들은 고객의 월별 청구금액을 계산하기 위해 주기적으로 일괄처리된다. 데이터베이스는 매일 수백만 건의 새로운 레코드를 저장하며 고객의 청구서 정보는 적어도 1년 동안 유지한다.


또한, 데이터베이스는 주기적으로 백업되고, 그것이 분산 데이터베이스가 될 수 있기에 모든 레코드는 한 군데 이상의 물리적인 위치에 저장된다. 사실, 어떤 주어진 시간에 약 20억 개의 레코드들이 데이터베이스의 다른 백업 생성들 및 분산된 부분들에 저장될 수도 있다.


최소한의 청구서 레코드는 고객의 ID, 통화시간 기록, 통화의 종류(예를 들면 지역 또는 장거리)를 나타내는 코드들 그리고 통화 요율(off peak, peak time)을 포함한다.


BPM-Business-Process-Management-Consulting-Services[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields)


문자 그대로 모든 비트는 가치를 가진다(하나의 잉여 비트는 2.5 GB의 메모리 낭비를 함축한다. 청구서 레코드의 비)공간 최적화(non-space-optimizing) 정의는 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct BillingRec
{
    long cust_id;
    long timestamp;
 
    enum CallType
    {
        toll_free,
        local,
        regional,
        long_distance,
        international,
        cellular
    } type;
 
    enum CallTariff
    {
        off_peak,
        medium_rate,
        peak_time
    } tariff;
};
cs


BillingRec는 나의 32-비트 머신상에서 16바이트만큼 메모리를 차지한다. 공간은 여기에서 낭비된다.

예상대로 첫 번째 두 필드는 각각 4바이트를 차지한다. 그러나 두 enum 변수들은 한 바이트 이하로 안전하게 표현될 수 있음에도 8바이트를 차지한다.


BillingRec의 조정된 버전은 enum 값들을 두 개의 비트 필드들로 압착할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct BillingRec
{
    long cust_id;
    long timestamp;
 
    enum CallType
    {
        toll_free,
        local,
        regional,
        long_distance,
        international,
        cellular
    };
 
    enum CallTariff
    {
        off_peak,
        medium_rate,
        peak_time
    };
 
    unsigned call: 3;   // 세 개의 비트들
    unsigned tariff: 2// 두 개의 비트들
};
cs


이제 BillingRec의 크기는 12바이트이다.


절약된 4바이트는 하루 당 수 메가바이트의 저장장소와 같다. 두 개의 비트 필드들은 총 다섯 비트를 차지하는데 그것은 한 바이트보다 적다. 그런 까닭에 BillingRec이 12바이트가 아니라 9바이트를 차지한다고 예상할 수 있다.


C++ 리펙토링 Bit Fields[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields)


문제는 컴파일러가 워드 경계로 BillingRec의 크기를 정렬하기 위해 비트 필드들 이후에 세 개의 추가적인 패딩 바이트들을 삽입한다는 것이다. 추가적인 padding 바이트들은 세 개의 낭비되는 바이트들의 댓가로 더 빠른 액세스 타임을 보장한다.


이러한 문제를 극복하기 위한 두 가지 방법이 존재


바이트 경계상에서의 정렬에 사용하기 위해 컴파일러의 설정을 변경할 수 있거나, 또는 전체적으로 8바이트에 도달하도록 다른 멤버들의 크기를 변경할 수 있다. 멤버들의 크기를 변경하는 것은 첫 번째 두 멤버들 또한 비트 필드들이 되어야 하므로 어느 정도 편법이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct BillingRec
{
    int cust_id: 24;   // 23 bits + 1 sign bit
    int  timestamp: 24;
 
    enum CallType
    {//...
    };
 
    enum CallTariff
    {//...
    };
 
    unsigned call: 3;
    unsigned tariff: 2;
};
cs


이번에는 BillingRec는 총 8바이트를 차지하는데 그것의 원래 크기의 반이다. 이 예제에서 절약되는 저장장소는 매년 10GB가 될 수 있다. 요즈음 자기저장 매체의 싼 가격들을 고려하면 몇천 달러 절약은 흥미를 일으키는 주장이 될 것 같지는 않다.


C++ 강좌 메모리 최적화[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields)


 - 그러나 더 작은 데이터 저장장소를 선호하는 또 다른 이유가 존재한다:


디지털 통신의 비용들. 분산된 데이터베이스는 여러 위치들에 있는 동기화되는 사본들을 가진다. 동기화 과정은 보통 중앙의 데이터베이스로부터 그것의 동기화되는 사본들로의 디지털 데이터 전송을 이용하여 이루어진다.


임대된 회선 상에서 수 백만 개 레코드들의 전송은 매우 비싸다. 그러나 이들 회선을 소유하는 전화회사를 위하여 이것은 걱정거리가 아니다. 그러나 회사가 매시간 데이터 전송을 위하여 수백 달러를 지출하는 국제적인 은행이라고 가정하자. 이러한 경우에 데이터의 크기를 반으로 줄이는 것은 논의할 여지 없이 이득이다. 


기억해야 할 또 다른 것은 Web이다


만일 전화회사가 고객들이 온라인으로 자신들의 청구서 정보를 볼 수 있도록 하는 웹 사이트를 가진다면 아날로그 다이얼 회선을 통한 수 백 개 레코드들의 다운로드 시간은 성능조정에 의해 반으로 줄어들 수 있다.


[C++강좌] 메모리 최적화, 리펙토링 (Bit Fields 프로그래밍 성능 관리)

댓글