Я пытаюсь выяснить, сколько памяти занимают мои объекты, чтобы увидеть, сколько из них попадает в Куча больших объектов (что составляет более 85 000 байт).
Это так же просто, как добавить 4 для int, 8 для long, 4 (или 8, если вы используете 64-разрядную версию) для любых ссылочных типов и т. д. Для каждого объекта, или есть накладные расходы на методы, свойства и т. д.?
См. Этот вопрос [Получение размера поля в байтах с помощью C#] [1] и, в частности, [ответ Джона Скитса] [2] По сути, это не так просто как... [1]: stackoverflow.com/questions/207592/… [2]: stackoverflow.com/questions/207592/…





Не забывайте, что размер реального объекта не включает размер каких-либо объектов, на которые он ссылается.
Единственное, что может оказаться в куче больших объектов, - это массивы и строки - другие объекты имеют тенденцию быть относительно небольшими сами по себе. Даже объект с (скажем) 10 переменными ссылочного типа (по 4 байта на x86) и 10 идентификаторами GUID (каждый по 16 байтов) займет всего около 208 байт (есть небольшие накладные расходы на ссылку на тип и блок синхронизации).
Аналогичным образом, думая о размере массива, не забывайте, что если тип элемента является ссылочным типом, то для самого массива учитывается только размер использованная литература. Другими словами, даже если у вас есть массив из 20 000 элементов, размер самого объекта массива будет чуть более 80 КБ (на x86), даже если он ссылается на гораздо больше данных.
Если это не тип с огромным значением или тип экземпляра (т.е. многие тысячи полей), единственные типы, о которых вам нужно беспокоиться, - это большие массивы или строки. Конечно, чтобы определить размер массива, вам нужно знать размер элемента.
.NET (в настоящее время) выравнивает типы почти так же, как собственные компиляторы выравнивают типы. Фундаментальные типы имеют естественное выравнивание, которое обычно представляет собой округленную интегральную степень двух ближайших к их размеру:
Single, Int32, UInt32 - 4
IntPtr, UIntPtr, pointers, references - 4 on 32-bit, 8 on 64-bit
Double, Int64, UInt64 - 8
Char, Int16, UInt16 - 2
Byte, SByte - 1
При сборке типа компилятор будет следить за тем, чтобы все поля любого заданного типа имели начальное смещение внутри экземпляра, выровненное по границе, соответствующей этому типу - при условии, что явный макет не используется.
Сами типы, определяемые пользователем, имеют выравнивание, которое вычисляется как высшее выравнивание любого из их типов полей. При необходимости размер шрифта увеличивается, чтобы выровнять размер шрифта.
Но, конечно, все ссылочные типы по-прежнему имеют размер и выравнивание только IntPtr.Size, поэтому размер ссылочного типа не повлияет на массивы этого типа.
Обратите внимание, что среда CLR может по своему усмотрению выбирать типы макета, отличные от описанных выше, возможно, для увеличения локальности кеша или уменьшения заполнения, требуемого выравниванием.
Вы попадаете в область продвинутой отладки .NET. Начните с Отладочные книги Джона Робинса.
Используйте WinDBG с Sos.dll (часть дистрибутива .NET) и расширениями Sosex.dll. С помощью этих инструментов вы действительно можете увидеть, что происходит, когда ваше приложение работает. Вы найдете ответы на поставленные выше вопросы.
(Еще одна рекомендация - установить Интерфейс командной строки с общим исходным кодом 2.0, также известный как Rotor 2, чтобы посмотреть, что происходит под капотом.)
Если можете - сериализуйте это!
Dim myObjectSize As Long
Dim ms As New IO.MemoryStream
Dim bf As New Runtime.Serialization.Formatters.Binary.BinaryFormatter()
bf.Serialize(ms, myObject)
myObjectSize = ms.Position
К сожалению, если вы сериализуете объект, вы также сериализуете все объекты, на которые он ссылается.
+1, потому что это то, что я действительно хотел узнать (а не только размер ссылок)
@MatthewSteeples, объект без компонентов, это пустой объект, поэтому, если вам нужен «размер» вашего контейнера, он должен включать размеры компонентов.
@serhio, да, но для LOH размер ссылочных объектов не имеет значения. Каждый отдельный объект хранится в своем собственном месте, и я просто пытался определить, есть ли простой способ узнать, всегда ли какой-либо из наших объектов находится в LOH.
Вниз, говорит Барри Келли, Integer = 4, 8 or 2 Bytes Но в приведенном выше коде ms.Position показывает 54 в случае целого числа. Пожалуйста, помогите мне понять, почему это так.
Размер сериализованного объекта не обязательно совпадает с размером живого объекта в памяти, поэтому это решение фактически измеряет другое.
Пожалуйста, выполните следующие действия, чтобы узнать размер объекта.
Перейдите в Свойства проекта Visual Studio 2010 → вкладка Отлаживать → Включить отладку неуправляемого кода.
Перейдите в меню Visual Studio Отлаживать → Параметры и настройки → Отладка → Символы.
Там включите Microsoft Symbol Server и оставьте значение по умолчанию (символы могут начать загрузку).
Установите точку останова в своем коде, начните отладку (F5).
Откройте Отлаживать → Окна → Немедленное окно.
Введите .load sos.dll (Сын забастовки).
Введите *!DumpHeap -type MyClass* (объект, размер которого вы хотите найти)
На выходе найдите адрес объекта, то есть (00a8197c)
Размер MT адреса 00a8197c 00955124 36
Далее !ObjSize 00a8197c
Вот и все → sizeof (00a8197c) = 12 (0x48) байт (MyClass)
Не знал, что вы можете использовать sos.dll в Visual Studio. Действительно полезно, спасибо. Также может быть полезно отметить, что sos.dll не загружается, если приложение находится в 64-битном режиме. См. stackoverflow.com/a/3548129/442078
Однако убедитесь, что вы понимаете «недостатки» !ObjSize. Он будет учитывать циклы в графе вашего объекта. Например, если у вас есть словарь со значениями, которые ссылаются на сам словарь, каждое значение будет иметь "ObjSize" всего словаря.
Метод Гомеша упрощено:
Перейдите в Visual Studio (2010) Project Properties * → вкладка Отлаживать → Включить отладку неуправляемого кода.
Установите точку останова в своем коде, начните отладку (F5).
Откройте Отлаживать → Окна → Немедленное окно.
Введите .load sos.
Enter (замените myObject на имя вашего объекта)
? String.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(myObject).GetHandleValue()).ToString())
Используйте результат как параметр !ObjSize
См .: SOS.DLL, адрес объекта и отладчик Visual Studio Введение
Пример (ищем объект с именем tbl):
.load sos
extension C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll loaded
? string.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(tbl).GetHandleValue()).ToString())-4)
"27ccb18"
!ObjSize 27ccb18
PDB symbol for clr.dll not loaded
sizeof(027ccb18) = 154504 ( 0x25b88) bytes (System.Data.DataTable)
Для оценки (в 2017 г.) вы можете выполнить отладку в своем приложении, установить точку останова до того, как ваш словарь оживет, сделать «Снимок использования памяти» (вкладка: Использование памяти под Диагностические инструменты), заполнить словарь и получить еще один снимок.
Это неточно, но это хорошее предположение.
Связанный вопрос: sizeof Эквивалент для ссылочных типов