SlideShare a Scribd company logo
Урок 23. Паттерн 15. Рост размеров
структур
Сам по себе рост размера структур не является ошибкой, но может приводить к потреблению
необоснованного количества памяти и в результате к замедлению скорости работы программы.
Будем рассматривать данный паттерн не как ошибку, но как причину неэффективности 64-битного
кода.

Данные в структурах в языке Си++ выравниваются таким образом, чтобы обеспечить более
эффективный к ним доступ. Некоторые микропроцессоры вообще не могут напрямую обращаться
к не выровненным данным и компилятору приходиться генерировать специальный код для
обращения к таким данным. Те же микропроцессоры, которые могут обращаться к не
выровненным данным, все равно делают это намного менее эффективно. Поэтому компилятор
Си++ оставляет пустые ячейки между полями структур, чтобы обеспечить их выравнивание по
адресам машинных слов и тем самым ускорить к ним обращение. Можно отключить
выравнивание, используя специальные директивы #pragma, чтобы сократить объем используемой
памяти, но нас этот вариант сейчас не интересует. Часто можно значительно сократить объем
расходуемой памяти простым изменением порядка полей в структуре, без потери
производительности.

Рассмотрим следующую структуру:

struct MyStruct

{

    bool m_bool;

    char *m_pointer;

    int m_int;

};

На 32-битной системе эта структура займет 12 байт, и сократить этот размер не представляется
возможным. Каждое поле выровнено по границе 4 байта. Даже если m_bool перенести в конец,
это ничего не изменит. Компилятор все равно сделает размер структуры кратным 4 байтам для
выравнивания таких структур в массивах.

В случае 64-битной сборки структура MyStruct займет уже 24 байта. Это понятно. В начале идет
один байт под m_bool и 7 неиспользуемых байт для выравнивания, так как указатель занимает 8
байт и должен быть выровнен по границе 8 байт. Затем 4 байта для m_int и 4 неиспользуемых
байта, для выравнивания структуры по границе 8 байт.

К счастью, дело можно легко поправить, переместив m_bool в конец структуры, как показано
ниже:

struct MyStructOpt

{
char *m_pointer;

  int m_int;

  bool m_bool;

};

Структура MyStructOpt займет уже не 24, а 16 байт. Визуально расположение полей представлено
на рисунке 1. Весьма существенная экономия, если мы будем использовать, например, 10
миллионов элементов. В этом случае мы сэкономим 80 мегабайт памяти, но что еще более важно,
можем повысить производительность. Если структур будет немного, то нет разницы, какого они
размера. Доступ будет происходить с одинаковой скоростью. Но когда элементов много, то
начинает играть роль кэш, количество обращений к памяти и так далее. И можно с уверенностью
утверждать, что обработка 160 мегабайт данных займет меньше времени, чем 240 мегабайт. Даже
простой доступ ко всем элементам массива для чтения, уже будет более быстр.




             Рисунок 1 - Расположение полей в структурах MyStruct и MyStructOpt

Не всегда изменение последовательности полей в структурах возможно или удобно. Но если
таких структур миллионы, то следует не пожалеть немного времени на рефакторинг. Результат
такой простой оптимизации, как изменение последовательности полей, может дать весьма
впечатляющие результаты.

Вы, наверное, зададите вопрос, по каким правилам компилятор выравнивает данные. Мы
ответим кратко, а если интересно познакомиться с этой темой более подробно, то мы отсылаем
вас к книге Джеффри Рихтер - Создание эффективных WIN32-приложений с учетом специфики 64-
разрядной версии Windows. Там этот вопрос рассматривается достаточно подробно.

В целом правило выравнивание следующее: каждое поле выравнивается по адресу, кратному
размеру данного поля. Поле типа size_t на 64-битной системе будет выровнено по границе 8 байт,
int по границе 4 байта, short по границе 2 байта. Поля типа char не выравниваются. Размер
структуры выравнивается до размера, кратному размеру его максимального элемента. Поясним
это выравнивание на примере:

struct ABCD

 {

  size_t m_a;
char m_b;

 };

Элементы займут 8 + 1 = 9 байт. Но если размер структуры будет 9 байт, то, если мы захотим
создать массив структур ABCD[2], поле m_a второй структуры будет лежать по не выровненному
адресу. Вследствие этого компилятор дополнит структуру 7 пустыми байтами до размера 16 байт.

Может показаться сложным процесс оптимизации последовательности полей. Но можно
предложить очень простой и очень эффективный способ. Достаточно расположить поля в порядке
убывания их размера. Этого будет совершенно достаточно. В этом случае поля начнут
располагаться без лишних зазоров. Например, возьмем следующую структуру размером 40 байт

struct MyStruct

{

    int m_int;

    size_t m_size_t;

    short m_short;

    void *m_ptr;

    char m_char;

};

и простой сортировкой последовательности полей по убыванию размера:

struct MyStructOpt

{

    void *m_ptr;

    size_t m_size_t;

    int m_int;

    short m_short;

    char m_char;

};

мы сделаем из нее структуру размером всего 24 байт.


Диагностика
Инструмент PVS-Studio позволяет обнаружить структуры в коде 64-битных приложений,
перестановка полей в которых, позволит сократить их размер. На неоптимальные структуры
анализатор выдает диагностическое сообщение V401.
Анализатор не всегда выдает сообщение о неэффективности структур, так как старается сократить
количество излишних предупреждений. Например, анализатор не выдает предупреждение на
сложные классы, являющимися наследниками, поскольку такие объекты обычно создаются в
малом количестве. Пример:

class MyWindow : public CWnd {

  bool m_isActive;

  size_t m_sizeX, m_ sizeY;

  char m_color[3];

  ...

};

Размер данной структуры может быть сокращен, но это не имеет практического смысла.

Авторы курса: Андрей Карпов (karpov@viva64.com), Евгений Рыжков (evg@viva64.com).

Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++"
является ООО "Системы программной верификации". Компания занимается разработкой
программного обеспечения в области анализа исходного кода программ. Сайт компании:
http://www.viva64.com.

Контактная информация: e-mail: support@viva64.com, 300027, г. Тула, а/я 1800.

More Related Content

Similar to Урок 23. Паттерн 15. Рост размеров структур

Оптимизация 64-битных программ
Оптимизация 64-битных программОптимизация 64-битных программ
Оптимизация 64-битных программ
Tatyanazaxarova
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
Tatyanazaxarova
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Tatyanazaxarova
 
Особенности разработки 64-битных приложений
Особенности разработки 64-битных приложенийОсобенности разработки 64-битных приложений
Особенности разработки 64-битных приложений
Tatyanazaxarova
 
20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу
Tatyanazaxarova
 
Что такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_tЧто такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_t
Tatyanazaxarova
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
Tatyanazaxarova
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
Tatyanazaxarova
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMerge
Tatyanazaxarova
 
Безопасность 64-битного кода
Безопасность 64-битного кодаБезопасность 64-битного кода
Безопасность 64-битного кода
Tatyanazaxarova
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
Tatyanazaxarova
 
Статический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложенийСтатический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложений
Tatyanazaxarova
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
Tatyanazaxarova
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Tatyanazaxarova
 
Коллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программахКоллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программах
Tatyanazaxarova
 
Оптимизация в мире 64-битных ошибок
Оптимизация  в мире 64-битных ошибокОптимизация  в мире 64-битных ошибок
Оптимизация в мире 64-битных ошибок
Tatyanazaxarova
 
Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...
Sergey Vasilyev
 
Статический анализ Си++ кода и новый стандарт языка C++0x
Статический анализ Си++ кода и новый стандарт языка C++0xСтатический анализ Си++ кода и новый стандарт языка C++0x
Статический анализ Си++ кода и новый стандарт языка C++0x
Tatyanazaxarova
 
паскаль 10кл 14
паскаль 10кл 14паскаль 10кл 14
паскаль 10кл 14
Ирина Куликова
 
64-битный конь, который умеет считать
64-битный конь, который умеет считать64-битный конь, который умеет считать
64-битный конь, который умеет считать
Tatyanazaxarova
 

Similar to Урок 23. Паттерн 15. Рост размеров структур (20)

Оптимизация 64-битных программ
Оптимизация 64-битных программОптимизация 64-битных программ
Оптимизация 64-битных программ
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
 
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кодаСравнение диагностических возможностей анализаторов при проверке 64-битного кода
Сравнение диагностических возможностей анализаторов при проверке 64-битного кода
 
Особенности разработки 64-битных приложений
Особенности разработки 64-битных приложенийОсобенности разработки 64-битных приложений
Особенности разработки 64-битных приложений
 
20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу20 ловушек переноса Си++ - кода на 64-битную платформу
20 ловушек переноса Си++ - кода на 64-битную платформу
 
Что такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_tЧто такое size_t и ptrdiff_t
Что такое size_t и ptrdiff_t
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMerge
 
Безопасность 64-битного кода
Безопасность 64-битного кодаБезопасность 64-битного кода
Безопасность 64-битного кода
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
 
Статический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложенийСтатический анализ кода для верификации 64-битных приложений
Статический анализ кода для верификации 64-битных приложений
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
 
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ LibraryИнтервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
Интервью с Анатолием Кузнецовым, автором библиотеки BitMagic C++ Library
 
Коллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программахКоллекция примеров 64-битных ошибок в реальных программах
Коллекция примеров 64-битных ошибок в реальных программах
 
Оптимизация в мире 64-битных ошибок
Оптимизация  в мире 64-битных ошибокОптимизация  в мире 64-битных ошибок
Оптимизация в мире 64-битных ошибок
 
Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...Правила статического анализа кода для диагностики потенциально опасных констр...
Правила статического анализа кода для диагностики потенциально опасных констр...
 
Статический анализ Си++ кода и новый стандарт языка C++0x
Статический анализ Си++ кода и новый стандарт языка C++0xСтатический анализ Си++ кода и новый стандарт языка C++0x
Статический анализ Си++ кода и новый стандарт языка C++0x
 
паскаль 10кл 14
паскаль 10кл 14паскаль 10кл 14
паскаль 10кл 14
 
64-битный конь, который умеет считать
64-битный конь, который умеет считать64-битный конь, который умеет считать
64-битный конь, который умеет считать
 

More from Tatyanazaxarova

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
Tatyanazaxarova
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Tatyanazaxarova
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
Tatyanazaxarova
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
Tatyanazaxarova
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
Tatyanazaxarova
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Tatyanazaxarova
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
Tatyanazaxarova
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
Tatyanazaxarova
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
Tatyanazaxarova
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
Tatyanazaxarova
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
Tatyanazaxarova
 
PVS-Studio
PVS-Studio PVS-Studio
PVS-Studio
Tatyanazaxarova
 
PVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеPVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируете
Tatyanazaxarova
 
Пояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteПояснения к статье про Copy-Paste
Пояснения к статье про Copy-Paste
Tatyanazaxarova
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Tatyanazaxarova
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
Tatyanazaxarova
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времени
Tatyanazaxarova
 
По колено в Си++ г... коде
По колено в Си++ г... кодеПо колено в Си++ г... коде
По колено в Си++ г... коде
Tatyanazaxarova
 
Статический анализ и регулярные выражения
Статический анализ и регулярные выраженияСтатический анализ и регулярные выражения
Статический анализ и регулярные выражения
Tatyanazaxarova
 

More from Tatyanazaxarova (20)

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
 
PVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложенийPVS-Studio, решение для разработки современных ресурсоемких приложений
PVS-Studio, решение для разработки современных ресурсоемких приложений
 
Статический анализ Си++ кода
Статический анализ Си++ кодаСтатический анализ Си++ кода
Статический анализ Си++ кода
 
PVS-Studio
PVS-Studio PVS-Studio
PVS-Studio
 
PVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируетеPVS-Studio научился следить за тем, как вы программируете
PVS-Studio научился следить за тем, как вы программируете
 
Пояснения к статье про Copy-Paste
Пояснения к статье про Copy-PasteПояснения к статье про Copy-Paste
Пояснения к статье про Copy-Paste
 
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
Использование анализатора PVS-Studio в процессе инкрементальной сборки в Micr...
 
Статический анализ и ROI
Статический анализ и ROIСтатический анализ и ROI
Статический анализ и ROI
 
Вечный вопрос измерения времени
Вечный вопрос измерения времениВечный вопрос измерения времени
Вечный вопрос измерения времени
 
По колено в Си++ г... коде
По колено в Си++ г... кодеПо колено в Си++ г... коде
По колено в Си++ г... коде
 
Статический анализ и регулярные выражения
Статический анализ и регулярные выраженияСтатический анализ и регулярные выражения
Статический анализ и регулярные выражения
 

Урок 23. Паттерн 15. Рост размеров структур

  • 1. Урок 23. Паттерн 15. Рост размеров структур Сам по себе рост размера структур не является ошибкой, но может приводить к потреблению необоснованного количества памяти и в результате к замедлению скорости работы программы. Будем рассматривать данный паттерн не как ошибку, но как причину неэффективности 64-битного кода. Данные в структурах в языке Си++ выравниваются таким образом, чтобы обеспечить более эффективный к ним доступ. Некоторые микропроцессоры вообще не могут напрямую обращаться к не выровненным данным и компилятору приходиться генерировать специальный код для обращения к таким данным. Те же микропроцессоры, которые могут обращаться к не выровненным данным, все равно делают это намного менее эффективно. Поэтому компилятор Си++ оставляет пустые ячейки между полями структур, чтобы обеспечить их выравнивание по адресам машинных слов и тем самым ускорить к ним обращение. Можно отключить выравнивание, используя специальные директивы #pragma, чтобы сократить объем используемой памяти, но нас этот вариант сейчас не интересует. Часто можно значительно сократить объем расходуемой памяти простым изменением порядка полей в структуре, без потери производительности. Рассмотрим следующую структуру: struct MyStruct { bool m_bool; char *m_pointer; int m_int; }; На 32-битной системе эта структура займет 12 байт, и сократить этот размер не представляется возможным. Каждое поле выровнено по границе 4 байта. Даже если m_bool перенести в конец, это ничего не изменит. Компилятор все равно сделает размер структуры кратным 4 байтам для выравнивания таких структур в массивах. В случае 64-битной сборки структура MyStruct займет уже 24 байта. Это понятно. В начале идет один байт под m_bool и 7 неиспользуемых байт для выравнивания, так как указатель занимает 8 байт и должен быть выровнен по границе 8 байт. Затем 4 байта для m_int и 4 неиспользуемых байта, для выравнивания структуры по границе 8 байт. К счастью, дело можно легко поправить, переместив m_bool в конец структуры, как показано ниже: struct MyStructOpt {
  • 2. char *m_pointer; int m_int; bool m_bool; }; Структура MyStructOpt займет уже не 24, а 16 байт. Визуально расположение полей представлено на рисунке 1. Весьма существенная экономия, если мы будем использовать, например, 10 миллионов элементов. В этом случае мы сэкономим 80 мегабайт памяти, но что еще более важно, можем повысить производительность. Если структур будет немного, то нет разницы, какого они размера. Доступ будет происходить с одинаковой скоростью. Но когда элементов много, то начинает играть роль кэш, количество обращений к памяти и так далее. И можно с уверенностью утверждать, что обработка 160 мегабайт данных займет меньше времени, чем 240 мегабайт. Даже простой доступ ко всем элементам массива для чтения, уже будет более быстр. Рисунок 1 - Расположение полей в структурах MyStruct и MyStructOpt Не всегда изменение последовательности полей в структурах возможно или удобно. Но если таких структур миллионы, то следует не пожалеть немного времени на рефакторинг. Результат такой простой оптимизации, как изменение последовательности полей, может дать весьма впечатляющие результаты. Вы, наверное, зададите вопрос, по каким правилам компилятор выравнивает данные. Мы ответим кратко, а если интересно познакомиться с этой темой более подробно, то мы отсылаем вас к книге Джеффри Рихтер - Создание эффективных WIN32-приложений с учетом специфики 64- разрядной версии Windows. Там этот вопрос рассматривается достаточно подробно. В целом правило выравнивание следующее: каждое поле выравнивается по адресу, кратному размеру данного поля. Поле типа size_t на 64-битной системе будет выровнено по границе 8 байт, int по границе 4 байта, short по границе 2 байта. Поля типа char не выравниваются. Размер структуры выравнивается до размера, кратному размеру его максимального элемента. Поясним это выравнивание на примере: struct ABCD { size_t m_a;
  • 3. char m_b; }; Элементы займут 8 + 1 = 9 байт. Но если размер структуры будет 9 байт, то, если мы захотим создать массив структур ABCD[2], поле m_a второй структуры будет лежать по не выровненному адресу. Вследствие этого компилятор дополнит структуру 7 пустыми байтами до размера 16 байт. Может показаться сложным процесс оптимизации последовательности полей. Но можно предложить очень простой и очень эффективный способ. Достаточно расположить поля в порядке убывания их размера. Этого будет совершенно достаточно. В этом случае поля начнут располагаться без лишних зазоров. Например, возьмем следующую структуру размером 40 байт struct MyStruct { int m_int; size_t m_size_t; short m_short; void *m_ptr; char m_char; }; и простой сортировкой последовательности полей по убыванию размера: struct MyStructOpt { void *m_ptr; size_t m_size_t; int m_int; short m_short; char m_char; }; мы сделаем из нее структуру размером всего 24 байт. Диагностика Инструмент PVS-Studio позволяет обнаружить структуры в коде 64-битных приложений, перестановка полей в которых, позволит сократить их размер. На неоптимальные структуры анализатор выдает диагностическое сообщение V401.
  • 4. Анализатор не всегда выдает сообщение о неэффективности структур, так как старается сократить количество излишних предупреждений. Например, анализатор не выдает предупреждение на сложные классы, являющимися наследниками, поскольку такие объекты обычно создаются в малом количестве. Пример: class MyWindow : public CWnd { bool m_isActive; size_t m_sizeX, m_ sizeY; char m_color[3]; ... }; Размер данной структуры может быть сокращен, но это не имеет практического смысла. Авторы курса: Андрей Карпов (karpov@viva64.com), Евгений Рыжков (evg@viva64.com). Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++" является ООО "Системы программной верификации". Компания занимается разработкой программного обеспечения в области анализа исходного кода программ. Сайт компании: http://www.viva64.com. Контактная информация: e-mail: support@viva64.com, 300027, г. Тула, а/я 1800.