Узнать размер .NET-объекта

Я пытаюсь выяснить, сколько памяти занимают мои объекты, чтобы увидеть, сколько из них попадает в Куча больших объектов (что составляет более 85 000 байт).

Это так же просто, как добавить 4 для int, 8 для long, 4 (или 8, если вы используете 64-разрядную версию) для любых ссылочных типов и т. д. Для каждого объекта, или есть накладные расходы на методы, свойства и т. д.?

Связанный вопрос: sizeof Эквивалент для ссылочных типов

John Sheehan 28.11.2008 05:03

См. Этот вопрос [Получение размера поля в байтах с помощью C#] [1] и, в частности, [ответ Джона Скитса] [2] По сути, это не так просто как... [1]: stackoverflow.com/questions/207592/… [2]: stackoverflow.com/questions/207592/…

Lasse V. Karlsen 27.11.2008 18:42
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
54
2
51 775
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

Не забывайте, что размер реального объекта не включает размер каких-либо объектов, на которые он ссылается.

Единственное, что может оказаться в куче больших объектов, - это массивы и строки - другие объекты имеют тенденцию быть относительно небольшими сами по себе. Даже объект с (скажем) 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

К сожалению, если вы сериализуете объект, вы также сериализуете все объекты, на которые он ссылается.

Matthew Steeples 06.07.2011 15:01

+1, потому что это то, что я действительно хотел узнать (а не только размер ссылок)

alldayremix 29.04.2013 16:23

@MatthewSteeples, объект без компонентов, это пустой объект, поэтому, если вам нужен «размер» вашего контейнера, он должен включать размеры компонентов.

serhio 03.05.2013 13:33

@serhio, да, но для LOH размер ссылочных объектов не имеет значения. Каждый отдельный объект хранится в своем собственном месте, и я просто пытался определить, есть ли простой способ узнать, всегда ли какой-либо из наших объектов находится в LOH.

Matthew Steeples 03.05.2013 15:20

Вниз, говорит Барри Келли, Integer = 4, 8 or 2 Bytes Но в приведенном выше коде ms.Position показывает 54 в случае целого числа. Пожалуйста, помогите мне понять, почему это так.

Ammar 22.12.2014 08:36

Размер сериализованного объекта не обязательно совпадает с размером живого объекта в памяти, поэтому это решение фактически измеряет другое.

stakx - no longer contributing 17.05.2017 15:57

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

  1. Перейдите в Свойства проекта Visual Studio 2010 → вкладка ОтлаживатьВключить отладку неуправляемого кода.

  2. Перейдите в меню Visual Studio ОтлаживатьПараметры и настройкиОтладкаСимволы.

  3. Там включите Microsoft Symbol Server и оставьте значение по умолчанию (символы могут начать загрузку).

  4. Установите точку останова в своем коде, начните отладку (F5).

  5. Откройте ОтлаживатьОкнаНемедленное окно.

  6. Введите .load sos.dll (Сын забастовки).

  7. Введите *!DumpHeap -type MyClass* (объект, размер которого вы хотите найти)

  8. На выходе найдите адрес объекта, то есть (00a8197c)

    Размер MT адреса 00a8197c 00955124 36

  9. Далее !ObjSize 00a8197c

  10. Вот и все → sizeof (00a8197c) = 12 (0x48) байт (MyClass)

Не знал, что вы можете использовать sos.dll в Visual Studio. Действительно полезно, спасибо. Также может быть полезно отметить, что sos.dll не загружается, если приложение находится в 64-битном режиме. См. stackoverflow.com/a/3548129/442078

Will 28.01.2013 21:52

Однако убедитесь, что вы понимаете «недостатки» !ObjSize. Он будет учитывать циклы в графе вашего объекта. Например, если у вас есть словарь со значениями, которые ссылаются на сам словарь, каждое значение будет иметь "ObjSize" всего словаря.

Christian.K 15.12.2014 10:47

Метод Гомеша упрощено:

  1. Перейдите в Visual Studio (2010) Project Properties * → вкладка ОтлаживатьВключить отладку неуправляемого кода.

  2. Установите точку останова в своем коде, начните отладку (F5).

  3. Откройте ОтлаживатьОкнаНемедленное окно.

  4. Введите .load sos.

  5. Enter (замените myObject на имя вашего объекта)

    ? String.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(myObject).GetHandleValue()).ToString())

  6. Используйте результат как параметр !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 г.) вы можете выполнить отладку в своем приложении, установить точку останова до того, как ваш словарь оживет, сделать «Снимок использования памяти» (вкладка: Использование памяти под Диагностические инструменты), заполнить словарь и получить еще один снимок.

Это неточно, но это хорошее предположение.

Другие вопросы по теме