Расположение памяти в массиве .NET
Вопрос
Каково расположение памяти в массиве .NET?
Возьмем, к примеру, этот массив:
Int32[] x = new Int32[10];
Я понимаю, что основная часть массива выглядит следующим образом:
0000111122223333444455556666777788889999
Где каждый символ равен одному байту, а цифры соответствуют индексам в массиве.
Кроме того, я знаю, что существует ссылка на тип и syncblock-index для всех объектов, поэтому приведенное выше может быть скорректировано с учетом этого:
ttttssss0000111122223333444455556666777788889999
^
+- object reference points here
Кроме того, необходимо сохранить длину массива, так что, возможно, это более правильно:
ttttssssllll0000111122223333444455556666777788889999
^
+- object reference points here
Является ли это полным?Есть ли еще данные в массиве?
Причина, по которой я спрашиваю, заключается в том, что мы пытаемся оценить, сколько памяти займет пара различных представлений в памяти довольно большого корпуса данных, а размер массивов варьируется довольно сильно, поэтому накладные расходы могут оказать большое влияние в одном решении, но, возможно, не так сильно в другом.
Итак, в принципе, для массива, сколько там накладных расходов, это в основном мой вопрос.
И перед тем, как массивы - это плохо команда просыпается, эта часть решения представляет собой статическую сборку типа "один раз-ссылка-часто", поэтому использование расширяемых списков здесь не обязательно.
Решение
Отличный вопрос.Я нашел это статья, которая содержит блок-схемы как для типов значений, так и для ссылочных типов.Также смотрите на это Статья в котором Ритчер заявляет:
[snip] каждый массив содержит некоторую дополнительную служебную информацию, связанную с ним.Эта информация содержит ранг массива (количество измерений), нижние границы для каждого измерения массива (почти всегда 0) и длину каждого измерения.Служебные данные также содержат тип каждого элемента в массиве.
Другие советы
Один из способов проверить это - посмотреть на код в WinDbg.Итак, учитывая приведенный ниже код, давайте посмотрим, как это отображается в куче.
var numbers = new Int32[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Первое, что нужно сделать, это найти экземпляр.Поскольку я сделал это локальным в Main()
, легко найти адрес экземпляра.
Из адреса мы можем вывести фактический экземпляр, который дает нам:
0:000> !do 0x0141ffc0
Name: System.Int32[]
MethodTable: 01309584
EEClass: 01309510
Size: 52(0x34) bytes
Array: Rank 1, Number of elements 10, Type Int32
Element Type: System.Int32
Fields:
None
Это говорит нам о том, что это наш массив Int32 с 10 элементами и общим размером 52 байта.
Давайте создадим дамп памяти, в которой находится экземпляр.
0:000> d 0x0141ffc0
0141ffc0 [84 95 30 01 0a 00 00 00-00 00 00 00 01 00 00 00 ..0.............
0141ffd0 02 00 00 00 03 00 00 00-04 00 00 00 05 00 00 00 ................
0141ffe0 06 00 00 00 07 00 00 00-08 00 00 00 09 00 00 00 ................
0141fff0 00 00 00 00]a0 20 40 03-00 00 00 00 00 00 00 00 ..... @.........
01420000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
01420010 10 6d 99 00 00 00 00 00-00 00 01 40 50 f7 3d 03 .m.........@P.=.
01420020 03 00 00 00 08 00 00 00-00 01 00 00 00 00 00 00 ................
01420030 1c 24 40 03 00 00 00 00-00 00 00 00 00 00 00 00 .$@.............
Я вставил скобки для 52 байт.
- Первые четыре байта являются ссылкой на таблицу методов в 01309584.
- Затем четыре байта для длины массива.
- Далее следуют числа от 0 до 9 (каждые четыре байта).
- Последние четыре байта равны нулю.Я не совсем уверен, но предполагаю, что именно там должна храниться ссылка на массив syncblock, если экземпляр используется для блокировки.
Редактировать:Забыл длину в первом постинге.
Список немного некорректен, потому что, как указывает ромкинс, экземпляр фактически начинается с адреса - 4, а первым полем является Syncblock .
Отличный вопрос!Я хотел увидеть это сам, и это показалось мне хорошей возможностью попробовать CorDbg.exe...
Похоже, что для простых целочисленных массивов формат равен:
ssssllll000011112222....nnnn0000
где s - блок синхронизации, l - длина массива, а затем отдельных элементов.Кажется, что в конце есть, наконец, 0, я не уверен, почему это так.
Для многомерных массивов:
ssssttttl1l1l2l2????????
000011112222....nnnn000011112222....nnnn....000011112222....nnnn0000
где s - блок синхронизации, t - общее количество элементов, l1 - длина первого измерения, l2 - длина второго измерения, затем два нуля?, за которыми последовательно следуют все элементы и, наконец, снова ноль.
Массивы объектов обрабатываются как целочисленный массив, на этот раз содержимым являются ссылки.Зубчатые массивы - это массивы объектов, ссылки на которые указывают на другие массивы.
Объект array должен был бы хранить, сколько измерений он имеет, и длину каждого измерения.Таким образом, в вашу модель можно добавить по крайней мере еще один элемент данных