Принятый ответ неправильный, он игнорирует выравнивание. Размер структуры - это не просто сумма ее членов. Может потребоваться дополнительное пространство между полями и концом структуры, чтобы помочь процессору эффективно считывать поле и реализовывать гарантии атомарности, предоставляемые моделью памяти .NET.
Это сложная функция для DateTimeOffset, программа Microsoft, которая написала структуру DateTimeOffset, сделала большую ошибку, начав код путем копирования/вставки структуры DateTime. Которая имеет историческую ошибку, которая имеет большое значение для DateTimeOffset, поскольку она имеет два поля вместо одного. Он использует LayoutKind.Auto вместо Sequential. Легко видны в Reference Source
Это дает свободу действий CLR, чтобы организовать поля оптимальным в любом режиме он работает. В 32-битном режиме он не выравнивать Int64 8 байт, как это обычно , но до 4 байтов. Это добавляет меньше полей между полями, размер которых составляет 12 байтов.
Аналогично, в 64-битном режиме ему нравится выравнивать поля до 8. Это создает больше полей между полями.
Единственный хороший способ увидеть это с помощью отладчика. Выполнить этот бит кода:
static void Main(string[] args) {
var arr = new DateTimeOffset[] {
new DateTimeOffset(0x123456789abcdef0, TimeSpan.FromMinutes(60)),
new DateTimeOffset(0x123456789abcdef0, TimeSpan.FromMinutes(60)),
};
System.Diagnostics.Debugger.Break();
}
Когда хиты точки останова, используйте Debug> Windows> Память> Memory1 и тип &arr[0]
в поле Адрес, чтобы посмотреть на содержимое массива. Вы увидите что-то похожее на:
0x00000115DC4FBA30 3c 00 00 00 00 00 00 00 f0 76 f8 38 70 56 34 12 <.......ðvø8pV4.
0x00000115DC4FBA40 3c 00 00 00 00 00 00 00 f0 76 f8 38 70 56 34 12 <.......ðvø8pV4.
0x00000115DC4FBA50 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Вы можете легко увидеть Offset поле (60 = 0x003c) и поле DateTime.Я изменил размер окна, сделав 2 элемента очевидными, он не будет выглядеть так чисто на вашей машине :) Но просто пересчитайте байты до тех пор, пока они не повторятся, DateTimeOffset принимает 16 байтов в 64-битном режиме.
Тот факт, что размер отличается между 32-битным и 64-битным режимами, должен в целом беспокоить вас. Эта ошибка в противном случае никогда не требовалась для исправления, нет разумной истории взаимодействия для DateTimeOffset, она никогда не соответствует эквивалентному неуправляемому типу. Это назначенный тип взаимодействия в WinRT (иначе UWP), но языковая проекция, встроенная в CLR, скрывает проблему.
+1 Спасибо за решение моей оригинальной проблемы. Я думал об этом в своем веб-приложении, но я не мог гарантировать, что он был потокобезопасным, поскольку могут возникать многочисленные запросы. –
В какой-то степени вы можете уменьшить чувствительность этого трюка к другим влияниям за счет увеличения sz. Однако этот код временно сжигает кусок памяти, поэтому он не идеален для использования в производстве. Однако вы можете просто развернуть новый экземпляр Azure, запустить код, а затем отбросить экземпляр. Во всяком случае, подход Ганса намного лучше, когда вам нужны надежные, точные цифры. Тем не менее, это подход, который я обычно использую, когда хочу оценить влияние новой функции приложения на память (в основном, для прогнозирования потребления памяти по порядку величины). – Brian