Re[2]: Размер объекта в куче
От: jazzer Россия Skype: enerjazzer
Дата: 28.10.05 14:33
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, xexe2, Вы писали:


X>>Уважаемый ол, чему же именно равен размер объекта в куче?


К>Во-первых. Размер объекта всегда равен sizeof(этот_объект), вне зависимости — в куче он, на стеке или статический.

К>То, что менеджер кучи тратит чуть больше памяти, чем этот sizeof (служебная информация, выравнивание, минимальный размер блока и его гранулярность) — предмет для отдельного разговора.

Таки выравнивание включено в sizeof, думается, и от метода аллокации не зависит (за исключением char, но сейчас речь не о том)
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[9]: Размер объекта в куче
От: __LP  
Дата: 28.10.05 14:34
Оценка: :))
Здравствуйте, sch, Вы писали:

C>>Правда, я где-то натыкался на информацию о том, что на самом деле выполнять оптимизацию для пустых базовых классов нельзя.

C>>Ну, вроде как, в стандарте ошибка была.

sch>ААААА!

sch>Я в панике!
sch>Если ты помнишь ссылку или она где-то у тебя осталась, то дай мне ее пожалуйста!
sch>Нам через неделю проект сдавать, а у empty base class optimisation используется очень активно!
Ничего страшного. Главное не говори об этом своему компилятору
C++ можно выучить за 21 день! ...если дни — полярные.
Re[10]: Размер объекта в куче
От: crable США  
Дата: 28.10.05 14:35
Оценка:
Здравствуйте, __LP, Вы писали:

__L>Здравствуйте, sch, Вы писали:


C>>>Правда, я где-то натыкался на информацию о том, что на самом деле выполнять оптимизацию для пустых базовых классов нельзя.

C>>>Ну, вроде как, в стандарте ошибка была.

sch>>ААААА!

sch>>Я в панике!
sch>>Если ты помнишь ссылку или она где-то у тебя осталась, то дай мне ее пожалуйста!
sch>>Нам через неделю проект сдавать, а у empty base class optimisation используется очень активно!
__L>Ничего страшного. Главное не говори об этом своему компилятору

Ага Компиляторы ее все равно делают.
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re[2]: Размер объекта в куче
От: Глеб Алексеев  
Дата: 28.10.05 14:35
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Здравствуйте, xexe2, Вы писали:


X>>Уважаемый ол, чему же именно равен размер объекта в куче?

Здорово, подробнее и яснее объяснить было нельзя .
Оказывается, я был неправ насчет new T[0].
Маленькое дополнение (может быть интересно xexe2): часто интереснее не sizeof(T), который одинаковый и в куче, и в стеке, а общий объем памяти, используемый объектом и созданными им внутренностями (например, для контейнеров — узлами деревьев/списков), его оценить в общем случае сложнее — или лезть в исходники реализации, скажем STL, если интересует объем памяти под контейнер, и умножать размер узла на количество узлов (для списков/деревьев), либо использовать профайлер памяти (я по своей темноте с таким до сих пор не сталкивался).
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Размер объекта в куче
От: srggal Украина  
Дата: 28.10.05 14:38
Оценка:
Здравствуйте, Кодт, Вы писали:

К>В-третьих, можно запросить массив нулевого размера на куче: new Type[0]; причём этот массив будет иметь ненулевой указатель.

К>Зачем так сделано — нужно подумать или порыться в Стандарте.
К>В С++ есть 3 вида валидных указателей:
К>- нулевой (нельзя разыменовывать, неприменима адресная арифметика, приводится к false)
К>- указатель на существующий объект, в т.ч. в составе массива (можно разыменовывать, применима адресная арифметика, приводится к true)
К>- указатель за концом массива (нельзя разыменовывать, применима адресная арифметика, приводится к true)
К>new T[0], очевидно, даёт третью разновидность.

В БрэйнБэнч, помнится тоже вопросец был как раз на Sizeof( T ) == 0
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[9]: Размер объекта в куче
От: crable США  
Дата: 28.10.05 14:52
Оценка:
Здравствуйте, sch, Вы писали:

C>>Правда, я где-то натыкался на информацию о том, что на самом деле выполнять оптимизацию для пустых базовых классов нельзя.

C>>Ну, вроде как, в стандарте ошибка была.

sch>ААААА!

sch>Я в панике!
sch>Если ты помнишь ссылку или она где-то у тебя осталась, то дай мне ее пожалуйста!
sch>Нам через неделю проект сдавать, а у empty base class optimisation используется очень активно!

Ссылку не нашел , но вроде я это видел в comp.lang.c++.moderated.
Сейчас там немного порылся, нашел вот это.
Не то, что я имел в виду, но тоже интересно.
The last good thing written in C was Franz Schubert's Symphony No. 9.
Re[2]: Размер объекта в куче
От: xexe2  
Дата: 28.10.05 14:52
Оценка:
спасибо конечно кодт
и всем остальным пытавшимся меня запутать насчет того что размер объекта может быть равено 0 тоже спасибо
из всего топика сформировал ответ следующий:

размер объекта равен:
положительному целому, равному сумме размеров полей + 1 ссылка(размером 4 байта) на таблицу виртуальных методов если она конечно есть
ну вроде и все:)
Re[3]: Размер объекта в куче
От: srggal Украина  
Дата: 28.10.05 15:04
Оценка:
Здравствуйте, xexe2, Вы писали:

X>спасибо конечно кодт

X>и всем остальным пытавшимся меня запутать насчет того что размер объекта может быть равено 0 тоже спасибо
X>из всего топика сформировал ответ следующий:

X>размер объекта равен:

X>положительному целому, равному сумме размеров полей + 1 ссылка(размером 4 байта) на таблицу виртуальных методов если она конечно есть

Не забываем про множественное наследование
N-ссылок
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Размер объекта в куче
От: srggal Украина  
Дата: 28.10.05 15:05
Оценка:
Здравствуйте, srggal, Вы писали:

S>Здравствуйте, xexe2, Вы писали:


X>>спасибо конечно кодт

X>>и всем остальным пытавшимся меня запутать насчет того что размер объекта может быть равено 0 тоже спасибо
X>>из всего топика сформировал ответ следующий:

X>>размер объекта равен:

X>>положительному целому, равному сумме размеров полей + 1 ссылка(размером 4 байта) на таблицу виртуальных методов если она конечно есть

S>Не забываем про множественное наследование

S>N-ссылок

Причем и одной может не быть, если нет виртуальных методов в классе
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[3]: Размер объекта в куче
От: Кодт Россия  
Дата: 28.10.05 15:07
Оценка: 22 (2) +1
Здравствуйте, xexe2, Вы писали:

X>из всего топика сформировал ответ следующий:

X>размер объекта равен:
X>положительному целому, равному сумме размеров полей + 1 ссылка(размером 4 байта) на таблицу виртуальных методов если она конечно есть

Не совсем так.

1) Между полями могут быть промежутки, обеспечивающие выравнивание полей (управляется прагмой pack в VC или аттрибутом align в gcc)
2) В случае множественного наследования нужно учесть прихоти компилятора по оптимизации пустых баз (от 0 до 1 байта на каждую базу)
3) Кроме того, при множественном наследовании могут быть несколько указателей на vtbl (в каждой из баз с виртуальными методами)
4) При виртуальном наследовании появятся указатели на виртуальные базы (в каждой из баз, унаследованных виртуально) — впрочем, это зависит от реализации, смещение виртуальной базы может храниться как в объекте, так и в vtbl.
Перекуём баги на фичи!
Re[3]: Размер объекта в куче
От: FreshMeat Россия http://www.rsdn.org
Дата: 28.10.05 15:11
Оценка:
Здравствуйте, xexe2, Вы писали:

X>из всего топика сформировал ответ следующий:

X>размер объекта равен:
X>положительному целому, равному сумме размеров полей + 1 ссылка(размером 4 байта) на таблицу виртуальных методов если она конечно есть

Он равен тому, что возвращает sizeof.
Если оч. хочется считать виртуальные ф-ии, наследование (в т.ч. виртуальное) и т.д. читай http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/dnarvc/html/jangrayhood.asp (*)
При этом необходимо учитывать, что информация compiler-specific



(*) кто-то когда-то уже выкладывал эту статью на рсдн, но найти ссылку не удалось
Хорошо там, где мы есть! :)
Re[10]: Размер объекта в куче
От: Erop Россия  
Дата: 28.10.05 17:34
Оценка: +1 :)
Здравствуйте, Аноним, Вы писали:

А>>>sizeof(*(new T[0]))

ГА>>Попробуй sizeof(*(new T[1000000]))

А>ну так тоже 1 а мне надо 0.


Слышь, признайся, а что у тебя за компилятор, что sizeof( T* ) == sizeof( char )?
Интересно, что за платформа?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Размер объекта в куче
От: Erop Россия  
Дата: 28.10.05 17:36
Оценка: +1
Здравствуйте, jazzer, Вы писали:

J>Здравствуйте, Кодт, Вы писали:


К>>Здравствуйте, xexe2, Вы писали:


X>>>Уважаемый ол, чему же именно равен размер объекта в куче?


К>>Во-первых. Размер объекта всегда равен sizeof(этот_объект), вне зависимости — в куче он, на стеке или статический.

К>>То, что менеджер кучи тратит чуть больше памяти, чем этот sizeof (служебная информация, выравнивание, минимальный размер блока и его гранулярность) — предмет для отдельного разговора.

J>Таки выравнивание включено в sizeof, думается, и от метода аллокации не зависит (за исключением char, но сейчас речь не о том)


Большинство аллокаторов на что-то выравнивают блоки.
Попробуй поаллокировать, например char[129] и посмотри на адреса. Узнаешь много интересного
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Что вернёт sizeof?
От: Erop Россия  
Дата: 28.10.05 18:11
Оценка: 66 (10) -1 :)
#Имя: FAQ.cpp.sizeof
Здравствуйте, xexe2, Вы писали:

X>Уважаемый ол, чему же именно равен размер объекта в куче?


Собственно сначала отвечу про sizeof

На самом деле для любого типа в C++ можно вычислить, кроме sizeof ещё один параметр -- выравнивание.
Выравнивание -- это число, которому должны быть кратны смещения полей этого типа и которому должен быть кратен его sizeof.

Посчитать выравнивание можно, например, так:

template<typename T>
class Align {
    struct AlignStruct {
        char forAlign;
        T t;
    };
public:
    enum { Result = sizeof( AlignStruct ) - sizeof( T ) };
};


Используя эту конструкцию и sizeof можно поисследовать размеры разных объектов. А используя макрос OFFSET_OF ещё и смещениея разных явно заданных полей.

1) Для стандартных типов можно составить табличку.
2) Для случая структуры или класса без виртуальных методов и без предков размер и смещения полей вычисляются так:

текущее_смещение_поля = 0;
текущее_выравнивание_структуры = 1;
foreach( поля ) {
    текущее_выравнивание_структуры = max( текущее_выравнивание_структуры, align( текущее_поле ) );
    текущее_смещение_поля = округлить_вверх( текущее_смещение_поля, align( текущее_поле ) );
    разместить( текущее_поле, текущее_смещение_поля );
    текущее_смещение_поля += sizeof( текущее_поле );
}
размер_структуры = max( округлить_вверх( текущее_смещение_поля ), 1 );
выравнивание_структуры = текущее_выравнивание_структуры;


тут функция округлить_вверх( a, b ) возвращает наименьшее целое n, такое что a <= n и n кратно b

3) Для случая union в качестве выравнивания берётся максимальное выравнивание поля, а в качестве sizeof максимальный sizeof поля округлённый вверх на выравниване union

При этом не важно, сколь сложно устроены поля. Я пока не встретил ещё компилятора, который бы не придерживался такой стратегии. Тут в целом есть довольно мало места для произвола. Основное -- порядок итерации полей в приведённом выше алгоритме. Обычно они итерируются в порядке описания, но возможны варинаты. Немного спасает то, что для структур приходится всем компиляторам согласовывать свои правила, чтобы все могли звать API. Но в случае private секций руки у них уже довольно развязаны.

4) В классе, где есть виртуальные методы, обычно заводится дополнительные скрытыие поля, со своими sizeof и align. В принципе их можно воспринимать как поля стандартных типов. Соответсвенно поэкспериментировав с классами вида
class A { virtual ~A() {} };

Можно узанать значения sizeof и align этих переменных. Обычно они такие же, как и у указателя.

5) В случае простого нследования, объекты базовых типов размещаются в объекте наследнике по тому же алгоритму, что и поля. За исключением одной тонкости. Компилятор имеет право на оптимизацию, суть которой состоит в том, что можно вовсе не размещать объекты баз, в которых нет полей.
Но есть тонкости, в случае, когда есть виртуальные базы. Их всего две
5.1) Наличие виртуальной базы может порождать доп. скрытые поля (может и не порождать)
5.2) объект виртуальной базы всегда один, но вот выравнивание "остатков" от его наследников может быть разным. В целом обычно компиляторы ведут себя так, что "остаток" является как бы отдельным полем, а виртуальная база отодельным.

Собственно это примерно исчерпывает правила, которых обычно придержиываются компиляторе в вопросе определния sizeof объектов.

При этом стоит обратить вниание на то, что обычно есть параметр компиляции, который как бы задаёт максимальное выравнивание стандартного типа. Так что если вы какую-то структуру скомпилируете со значением этого параметра, скажем 2, то потом выравнивание этой структуры будет 2, что бы вы с ней не делали.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Размер объекта в куче (именно в куче, а не где-то ещё)
От: Erop Россия  
Дата: 28.10.05 18:32
Оценка: 7 (1)
Здравствуйте, xexe2, Вы писали:

X>Уважаемый ол, чему же именно равен размер объекта в куче?


могу поделиться своими отрывочными воспоминаниями о кучах.

1) когда ты пишешь что-то типа new MyType, то в кучу приходит запрос выделить тебе sizeof( MyType ) байт памяти.

При этом есть несколько особенностей. Болшинство куч при этом выделяет память с небольшим запасом (часто sizeof( int ) ), чтобы сохранить там размер блока, который понадобится при деаллокации. Но overhead обычно намного больше, так как оычно кучи выдают выравненные на что-ниублдь заметное (например на 16 ) адреса.
Кроме того кучи любят устраивать гарнуляцию выдеяемых размеров, особенно для мелких блоков. То есть вместо того чтобы выделять ровно столько памяти, сколько просят, выделяют немного больше. Это немног определятеся так. Естьк ак-то заданный набор чисел, щадающих предпочтительные размеры блока, и выбирается наименьший из "предпочтительных размеров"

При этом часто бывает ещё и так, что для мелких, средних и больших блоков используются разные способы их выделения, с разными накладными расходами.

Например майкрософтовская куча блоки превышающие 64 К выделяет непосредственно через VirtualAlloc, а у него совсем другие наклодные расходы.

При этом следует понимать ещё два аспекта. Когда куча что-то аллокирует, потом на ней этот объект освобождают, то куча фрагментируется. При этом она кушает память у системы и обычно уже не возвращает её. Так что в зависимости от степени фрагментации с каждым аллокированым блоком теряется ещё и сколько-то байт из-за фрагментации. А так как при не очень долгих алгоритмах фрагментация кучи может всё время расти, то в таких программах всё выглядит так, как будто часть кучи при её работе теряется безвозвратно. Если программа долго и интернсивно пользуется кучей и не фрагментирует её как-то злонамеренно, то современная куча в состоянии поддерживать степень фрагментации ен сильно выше 2 (это если мене не подводит мой склероз ), то есть на каждый аллокированый на куче байт, ещё один байт будет потерян из-за фрагментации.

итого, при долгой работе, приводящей к фрагментации кучи получим, что объект займёт на куче примерно overhead + sizeof * 2.

p. s.
Да, если пишешь new MyType[xxx], то кроме sizoef(MyType) * xxx, и обычного overhead обычновыделяется ещё и место под счётчик, куда сохраняется xxx

p. p. s.
при этом не надо забывать, что объекты, аллокируемые хоть на кучах, хоть где-то ещё, могут аллокировать внутри себя какие-то запчасти (скажем буфер для поял типа std::vector), которые в свою очередь будут кушать место
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[2]: Ошибочка :)
От: Erop Россия  
Дата: 29.10.05 06:02
Оценка:
ночью писал, забыл один аргументик
E>
E>текущее_смещение_поля = 0;
E>текущее_выравнивание_структуры = 1;
E>foreach( поля ) {
E>    текущее_выравнивание_структуры = max( текущее_выравнивание_структуры, align( текущее_поле ) );
E>    текущее_смещение_поля = округлить_вверх( текущее_смещение_поля, align( текущее_поле ) );
E>    разместить( текущее_поле, текущее_смещение_поля );
E>    текущее_смещение_поля += sizeof( текущее_поле );
E>}
E>размер_структуры = max( округлить_вверх( текущее_смещение_поля, текущее_выравнивание_структуры ), 1 );
E>выравнивание_структуры = текущее_выравнивание_структуры;
E>


приношу извинения.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[11]: Размер объекта в куче
От: Кодт Россия  
Дата: 29.10.05 07:11
Оценка: :)))
Здравствуйте, Erop, Вы писали:

E>Слышь, признайся, а что у тебя за компилятор, что sizeof( T* ) == sizeof( char )?

E>Интересно, что за платформа?

Два варианта: или микроконтроллер с ОЗУ 256 байт, или БЭСМ-6 с 50-битными ячейками памяти
Перекуём баги на фичи!
Re[12]: Размер объекта в куче
От: Erop Россия  
Дата: 29.10.05 11:45
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Два варианта: или микроконтроллер с ОЗУ 256 байт, или БЭСМ-6 с 50-битными ячейками памяти


Про первый я не подумал
Но всё равно прикольно
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Что вернёт sizeof?
От: TYuD  
Дата: 25.07.06 09:04
Оценка:
Здравствуйте, Erop, Вы писали:

E>1) Для стандартных типов можно составить табличку.


А как?

Потом в примере не сказано про функцию align(). Это она будет использовать составленную табличку?
Лучше этот вопрос уточнить. Тем более, что он вынесен в статью.

E>текущее_смещение_поля = 0;
E>текущее_выравнивание_структуры = 1;
E>foreach( поля ) {
E>    текущее_выравнивание_структуры = max( текущее_выравнивание_структуры, align( текущее_поле ) );
E>    текущее_смещение_поля = округлить_вверх( текущее_смещение_поля, align( текущее_поле ) );
E>    разместить( текущее_поле, текущее_смещение_поля );
E>    текущее_смещение_поля += sizeof( текущее_поле );
E>}
E>размер_структуры = max( округлить_вверх( текущее_смещение_поля ), 1 );
E>выравнивание_структуры = текущее_выравнивание_структуры;


С уважением Юрий.
Re[11]: Размер объекта в куче
От: MShura  
Дата: 25.07.06 10:58
Оценка:
E>Слышь, признайся, а что у тебя за компилятор, что sizeof( T* ) == sizeof( char )?
E>Интересно, что за платформа?

А что тут особенного?
Гарантировано лишь sizeof(T*) >= sizeof(char).
На некоторых платформах (например ADSP-TS201) sizeof(void*) = 1 = 32 бита = sizeof(char)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.