ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Categories:

Выравнивание данных в памяти компьютера

Простая маленькая программа из учебника Лафоре, демонстрирующая работу указателя this (стр.517):
#include <iostream>

class where
{
private:
    char charray[10];
public:
    void reveal()
        { std::cout << this << std::endl; }
};

int main()
{
    where w1, w2, w3;

    w1.reveal();
    w2.reveal();
    w3.reveal();

    return 0;
}

Понятно, что при каждом новом запуске программы будут выведены отличающиеся адреса, но нас интересуют, собственно, не адреса, а расстояние между ними. Вот пример результата работы программы:

(тут надо бы отметить, что я пользуюсь операционной системой «Windows 7 Профессиональная» и компилятором из среды «Visual Studio Community 2017»)

003AF8AC
003AF8A0
003AF894

Как я понимаю, то, что объекты записываются в память в обратном порядке (адрес объекта w3 младше адреса объекта w2, а адрес объекта w2 младше адреса объекта w1) обусловлено тем, что они хранятся в стеке, который работает по принципу LIFO («последним вошёл — первым вышел»).

И вот тут начинается интересное. Так как объекты в данном случае записываются в памяти компьютера впритык друг к другу, рядышком, то, по идее, разница между выведенными на экран адресами объектов должна быть равна размеру этих объектов.

Размер каждого объекта, как видно из определения класса в программе, равен 10 байтам (так как размер типа char равен одному байту, а единственным полем класса является массив типа char из 10 элементов). Однако, разница между выведенными на экран адресами объектов равна 12 байтам (помним, что адреса здесь указаны в шестнадцатиричной системе счисления):

003AF8AC – 003AF8A0 = C16 = 1210
003AF8A0 – 003AF894 = C16 = 1210

Нижний индекс указывает на систему счисления.

Почему так происходит? Дело в том, что быстродействие процессора повышается, если хранить данные по адресам, кратным машинному слову. Поэтому по умолчанию данные и сохраняются по таким адресам. То есть память используется неэкономно, зато повышается быстродействие. Подробнее об этом можно прочитать в википедии, но на русском статья об этом представляет малюсенький огрызок, на английском — статья гораздо полнее.

Так как в данном случае я создал 32-разрядное приложение, то размер машинного слова равен 4 байтам (32 бита). То есть процессору удобнее работать с данными, размер которых кратен 4 байтам: 4, 8, 12 и так далее. Размер нашего объекта 10 байт. Ближайший больший размер, удобный процессору, это 12 байт. Поэтому ради быстродействия для каждого нашего объекта размером в 10 байт выделяется область памяти размером в 12 байт, поэтому и разница между адресами соседних объектов получилась в 12 байт.

Чтобы это проверить, я уменьшил размер поля нашего класса (а, следовательно, и всех объектов этого класса) до 8 байт:
char charray[8];
Теперь разница между адресами, выведенными на экран, должна совпасть с размером объектов и должна быть равной 8 байтам. Результат работы измененной программы:
0035FC80
0035FC78
0035FC70
Так и есть:

0035FC80 – 0035FC78 = 816 = 810
0035FC78 – 0035FC70 = 816 = 810

Если же кровь из носу требуется записать объекты впритык рядышком в областях памяти размером, совпадающим с размером объектов (то есть без выравнивания по адресам, кратным машинному слову), то для этого можно дать указание компилятору с помощью спецификатора alignas (в качестве аргумента спецификатору должно быть задано целое число, показатель кратности; для наших целей удобно задать единицу, так как любое число делится на единицу без остатка). Например, изменим программу так:
class alignas(1) where
{
private:
    char charray[10];
public:
    void reveal()
        { std::cout << this << std::endl; }
};
Результат работы измененной программы:
0042FDDE
0042FDE8
0042FDF2
Рассчитываем разницы между адресами, они (как и требовалось) равны 10 байтам:

0042FDF2 – 0042FDE8 = A16 = 1010
0042FDE8 – 0042FDDE = A16 = 1010

Еще изменился порядок записи объектов в память. Теперь они записываются по принципу FIFO («первым вошёл — первым вышел»). Как я понимаю, теперь они сохраняются не в стеке, а в куче.
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments