|
Программирование >> Обобщенные обратные вызовы
Резюме Управление памятью в современных операционных системах может быть очень сложным, но это - только один из уровней управления памятью, имеющий значение для программ на С+ + . Стандартная библиотека предоставляет несколько других уровней, в первую очередь при помощи собственных примитивов для выделения и освобождения памяти, посредством стандартных контейнеров и распределителей, а также контейнеров и распределителей памяти, которые вы можете написать самостоятельно. Но когда вы запрашиваете память, знаете ли вы о том, что вы получите на самом деле, и во что это вам обойдется? Сколько памяти требуется стандартным контейнерам - в теории, и на практике? Именно об этом мы и поговорим в следующей задаче. Задача 21. Контейнеры в памяти. Часть 2: какие они на самом деле? Сложность: 3 Когда вы запрашиваете память - что вы знаете о том, что вы получите и во что в действительности это вам обойдется ? Сколько памяти используют стандартные контейнеры - теоретически, практически и в коде, который будет написан вами сегодня вечером ? Вопрос для новичка 1. Когда вы запрашиваете п байтов памяти с использованием new или mall ос, в самом ли деле вы используете п байтов памяти? Поясните, почему. Вопрос для профессионала 2. Сколько памяти используют различные стандартные контейнеры для хранения одинакового количества объектов одного и того же типа т? Решение Что попросишь, то получишь? 1. Когда вы запрашиваете п байтов памяти с использованием new или malloc, в самом ли деле вы используете п байтов памяти? Поясните, почему. Когда вы запрашиваете п байтов памяти с использованием new или malloc, в действительности вы используете как минимум п байтов памяти, поскольку обычно диспетчер памяти должен добавить определенное количество памяти сверх запрошенной вами. Обычно это накладные расходы, связанные с внутренними сфуктурами диспетчера памяти, размером и выравниванием объектов в памяти. Рассмотрим накладные расходы, связанные с внутренними структурами диспетчера памяти. В универсальной схеме распределения памяти (т.е. с не фиксированными размерами блоков) диспетчер памяти должен помнить о том, какой размер имеет каждый вьщеленный блок, чтобы знать, какое количество памяти должно быть освобождено при вызове оператора delete или функции free. Обычно диспетчер памяти хранит это значение в начале реально выделяемого блока памяти, возвращая вам указатель на вашу область памяти, которая располагается непосредственно после необходимой области памяти, зарезервированной для служебной информации (см. рис. 21.1). Конечно, это означает, что должна быть выделена дополнительная память для сохранения размера блока, т.е. для числа, достаточного для хранения значения, равного максимально возможному корректному запросу памяти; обычно для этой цели достаточно числа, размер которого равен размеру указателя. При освобождении блока диспетчер памяти получает переданный ему вами указатель, вычитает из него количество байтов системной информации, считывает раз.мер блока и выполняет его освобождение. Конечно, в схеме с фиксированным размером блока (которая возвращает блоки памяти данного заранее известного размера) хранение дополнительной информации о размере блока не требуется, поскольку размер блока и так всегда известен. Теперь рассмотрим расходы, связанные с размером и выравниванием объекта. Даже если не требуется хранение дополнительной информации, диспетчер памяти часто резервирует большее количество памяти, чем было запрошено, потому что память часто вьщеляется блоками определенного размера. Указатель, возвращаемый new или malloc Реально выделенный буфер
Системная информация Запрошенная вами память Рис. 21.1. Типичное выделение п байтов памяти С одной стороны, на некоторых платформах выдвигается требование того или иного расположения объектов определенных типов данных в памяти (например, некоторые платформы требуют размещения указателей по адресам, кратным 4), и в случае несоблюдения этих требований программа оказывается либо неработоспособной, либо скорость ее работы существенно снижается. Такое требование к размещению данных называется выравниванием (alignment) и приводит к необходимости затрат дополнительной памяти для заполнения промежутков внутри объекта и, возможно, за концом данных объекта. Выравнивание затрагивает даже обычные старые встроенные массивы С, поскольку вносит свой вклад в значение, возвращаемое sizeof(struct). На рис. 21.2 показана разница между внутренним заполнением и заполнением после конца объекта (хотя оба дают свой вклад в значение sizeof (struct)). тбайтов== sizeof (object) jK,
п байтов == размер каждого элемента данных + возможное внутреннее выравнивание Заполнение Рис. 21.2. Размещение в памяти .массива п-байтовых объектов с т-байтовым выравниванием (обратите внимание, что sizeof(object)==m) Например: пример 21-1: предполагается, что si zeof(long) == 4, и все значения long требуют выравнивания по 4-байтовой границе struct XI { char cl; Смешение О, размер - 1 байт Байты 13: 3 заполняющих байта long 1; Байты 4-7: 4 байта на 4-байтовой границе char с2; Байт 8: 1 байт Байты 9-11: заполняющих байтов (см. текст) }; sizeof(XI) == 12 В обозначениях рис. 21.2, в данном примере п 1 + 3 + 4 + 1 == 9 и m == si zeof (xl) == 12. Заметим, что в значение si zeof (х1) вносят вклад все заполнители - как внутренние, так и внешние. Может показаться, что внешнее заполнение за Только никуда негодная реализация может использовать заполняющие байты сверх минимально необходимого количества.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |