Тази статия е огледална статия за машинен превод, моля, кликнете тук, за да преминете към оригиналната статия.

Изглед: 537|Отговор: 1

[Източник] [Завърти]. Как NET/C# изчислява колко памет заема една инстанция?

[Копирай линк]
Публикувано на 27.08.2025 09:00:22 | | | |
Всички знаем, че процесорът и паметта са двата най-важни показателя за една програма, така че колко хора наистина са се замисляли за въпроса: Колко байта заема инстанция на даден тип (тип стойност или тип референтен тип) в паметта? Много от нас не могат да отговорят. C# предоставя някои оператори и API за изчисляване на размери, но нито един от тях не решава напълно проблема, който току-що зададох. Тази статия предоставя метод за изчисляване на броя на байтовете памет, заети от екземплярите на типове стойности и референтни типове. Изходният код се изтегля оттук.

1. Размер на оператора
2. Метод Marshal.SizeOf
3. Несигурен. Размер на метода >
4. Може ли да се изчисли според типа на полевия член?
5. Подредба на типовете стойности и типовете приложения
6. Директива на LDFLDA
7. Изчислете броя байтове от типа стойност
8. Преброй броя байтове от типа цитиране
9. Пълно изчисление

1. Размер на оператора

Размерът на операцията се използва за определяне на броя байтове, заети от екземпляр на даден тип, но може да се приложи само към неуправлявани типове. Т.нар. Неуправляван тип е ограничен до:

Примитивни типове: булев, байт, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, IntPtr, UIntPtr, Char, Double и Single)
Десетичен тип
Тип на изброяване
Тип указател
Структури, които съдържат само членове на данни от тип Unmanaged
Както подсказва името, неуправляван тип е тип стойност и съответният инстанция не може да съдържа никаква препратка към управлявания обект. Ако дефинираме общ метод като този, за да извикнем оператора sizeof, общият параметър T трябва да добави неуправлявано ограничение и небезопасен таг към метода.

Само нативни и enum типове могат да използват оператора за размера на оператора, който трябва да се добавя, ако се прилага към други типове (указатели и персонализирани структури)./unsafeКомпилационни тагове, а също така трябва да бъдат поставени вОпасниВ контекста.

Тъй като следващата структура Foobar не е тип Unmanage, програмата ще има грешка при компилацията.

2. Метод Marshal.SizeOf

Статични типове Маршал дефинира серия от API-та, които ни помагат да разпределяме и копираме неуправлявана памет, да конвертираме между управлявани и неуправлявани типове и да извършваме серия от други операции върху неуправлявана памет (Маршал в изчислителната наука се отнася до операцията за преобразуване на обекти в паметта в съответния формат за съхранение или трансфер на данни). Статичният, който включва следните 4 претоварвания на метода SizeOf, за да определи броя на байтовете от даден тип или обект.

Методът Marshal.SizeOf няма ограничение за зададения тип за Unmanaged типа, но все пак изисква да бъде посочен такъвТип стойност。 Ако входящият обект е обект, той трябва да бъде и кутия за тип стойност.

Тъй като следният Foobar е дефиниран като:вид, така че повикванията към двата метода SizeOf ще хвърлят изключение и подсказка ArgumentException: Тип 'Foobar' не може да бъде мобилизиран като неуправлявана структура; Не може да се изчисли значим размер или отместване.

Методът Marshal.SizeOfГенерични продукти не се поддържат, но също така има изисквания за разположението на конструкцията, което поддържа поддръжкатаПоследователнииИзриченРежим на оформление. Тъй като структурата на Foobar, показана по-долу, приема режим Auto layout (Auto, който не поддържа "динамично планиране" на подредба на паметта според елементи на полето поради по-строгите изисквания за разположение на паметта в неуправляеми среди), повикванията към метода SizeOf все още ще хвърлят същото изключение ArgumentException като по-горе.

3. Несигурен. Метод по размер

Статичният небезопасен осигурява повече ниско ниво операции за неуправляема памет, а подобни методи SizeIOf също са дефинирани в този тип. Методът няма ограничения за зададения тип, но ако зададеш референтен тип, той връщаБрой байтове на указателите"(IntPtr.Size)。

4. Може ли да се изчисли според типа на полевия член?

Знаем, че както типовете стойности, така и референтни типове се картографират като непрекъснат фрагмент (или се съхраняват директно в регистър). Целта на типа е да специфицира разположението на паметта на обект, а екземплярите от същия тип имат едно и също разположение и броят на байтовете е естествено същият (за полета с референтен тип се съхранява само реферираният адрес в тази байтова последователност). Тъй като дължината на байта се определя според типа, ако можем да определим типа на всеки член на полето, няма ли да можем да изчислим броя на байтовете, съответстващи на този тип? Всъщност това не е възможно.

Например, знаем, че байтовете байт, кратък, int и long са 1, 2, 4 и 8, така че броят на байтовете за байтов двоичен файл е 2, но за типова комбинация от байт + кратък, байт + int и байт + дълъг съответните байтове не са 3, 5 и 9, а 3, 8 и 16. Защото това включва въпроса за подравняване на паметта.

5. Подредба на типовете стойности и референтните типове

Броят на байтовете, заети от екземплярите на референтния тип и подтип, също е различен за един и същ член на данните. Както е показано на следващото изображение, байтовата последователност на екземпляра на типа стойностВсички са полеви служители, използвани за съхранение。 При примери на референтни типове, адресът на съответната таблица на метода също се съхранява пред последователността на байтовете на полето. Таблицата с методи предоставя почти всички метаданни, описващи типа, и използваме тази препратка, за да определим към кой тип принадлежи екземплярът. В самото начало има и допълнителни байтове, които ще наречемОбектен хедърТой не само се използва за съхранение на заключеното състояние на обекта, но и хеш стойността може да бъде кеширана тук. Когато създадем референтна тип променлива, тази променливаТой не сочи към първия байт памет, зает от инстанцията, а към мястото, където се съхранява адресът на таблицата с метод



6. Директива на LDFLDA

Както споменахме по-горе, операторът sizeof и методът SizeOf, предоставен от статичния тип Marshal/Unsafe, не могат наистина да решат изчисляването на дължината на байта, заети от екземпляри. Колкото знам, този проблем не може да се реши само в областта на C#, но се предоставя на ниво ILLdfldaИнструкциите могат да ни помогнат да решим този проблем. Както подсказва името, Ldflda означава Load Field Address, което ни помага да получим адреса на поле в инстанцията. Тъй като тази IL инструкция няма съответен API в C#, можем да я използваме само в следната форма чрез IL Emit.

Както е показано в горния откъс от кода, имаме метод GenerateFieldAddressAccessor в типа SizeCalculator, който генерира делегат от тип Func<object?, long[]> базиран на списъка с полета от посочения тип, което ни помага да върнем адреса на паметта на посочения обект и всички негови полета. С адреса на самия обект и адреса на всяко поле, естествено можем да получим отместването на всяко поле и лесно да изчислим броя байтове памет, заети от цялата екземпляр.

7. Изчислете броя байтове от типа стойност

Тъй като типовете стойности и референтните типове имат различни разположения в паметта, трябва да използваме и различни изчисления. Тъй като байтът на структурата е съдържанието на всички полета в паметта, използваме хитър начин да го изчислим. Да предположим, че трябва да определим броя байтове на структура от тип T, след което създаваме ValueTuple<T,T> кортеж, а отместването на второто му поле Item2 е броят байтове на структурата T. Конкретният метод за изчисление е отразен в следния метод CalculateValueTypeInstance.

Както е показано в горния откъс от кода, приемайки, че типът структура, който трябва да изчислим, е T, извикаме метода GetDefaultAsObject, за да получим обекта default(T) под формата на отражение, и след това създаваме ValueTuple<T,T>tt. След като извикаме метода GenerateFieldAddressAccessor, за да получим Func<object?, long[]> делегат за изчисляване на екземпляра и адресите на полета, извикваме този делегат като аргумент. За трите адреса в паметта, които получаваме, кодовият кортеж и адресите на полета 1 и 2 са еднакви, използваме третия адрес, представляващ елемент 2, минус първия адрес, и получаваме желания резултат.

8. Преброй броя байтове от типа цитиране

Изчисляването на байтове за референтни типове е по-сложно, като се използва тази идея: след като получим адреса на самата инстанция и всяко поле, сортираме адресите, за да получим отклонението на последното поле. Нека добавим този офсет към броя байтове на последното поле, а след това да добавим необходимите "първи и последни байтове" към желания резултат, което се отразява в следващия метод CalculateReferneceTypeInstance.

Както е показано в горния откъс от кода, ако посоченият тип няма дефинирани полета, CalculateReferneceTypeInstance връща минималния брой байтове от референтния тип екземпляр: 3 пъти броя на адресните указателни байтове. За x86 архитектури обектът от тип приложение заема поне 12 байта, включително ObjectHeader (4 байта), указатели за таблица на методи (байтове) и поне 4 байта съдържание на полето (тези 4 байта са необходими, дори ако няма дефиниран тип без полета). В случая с x64 архитектурата този минимален брой байтове ще бъде 24, тъй като указателят на таблицата на метода и минималното съдържание на полето ще станат 8 байта, въпреки че валидното съдържание на ObjectHeader заема само 4 байта, но отпред ще се добавят 4 байта допълване.

Разпределението на байтовете, заети от последното поле, също е много просто: ако типът е тип стойност, тогава методът CalculateValueTypeInstance, дефиниран по-рано, се извиква за изчисление; ако е референтен тип, съдържанието, съхранено в полето, е само адресът на паметта на целевия обект, така че дължината е IntPtr.Size. Тъй като инстанциите на референтния тип са подравнени с IntPtr.Size в паметта по подразбиране, това се прави и тук. Накрая, не забравяйте, че препратката на референтния тип не сочи към първия байт памет, а към байта, който съхранява указателя на таблицата за методи, така че трябва да добавите броя байтове на ObjecthHeader (IntPtr.Size).

9. Пълно изчисление

Двата метода, използвани за изчисляване на броя байтове на примери на стойностен тип и референтен тип, се използват в следния метод SizeOf. Тъй като извикването на инструкцията Ldflda трябва да предостави съответен екземпляр, този метод предоставя делегат за получаване на съответния екземпляр, освен че предоставя целевия тип. Параметрите, съответстващи на този делегат, могат да бъдат по подразбиране и ще използваме стойността по подразбиране за типа стойност. За референтни типове ще се опитаме да създадем целевия обект с помощта на стандартния конструктор. Ако този обект delegate не е предоставен и целевата инстанция не може да бъде създадена, методът SizeOf хвърля изключение. Въпреки че трябва да предоставим целевия екземпляр, изчисленият резултат е свързан само с типа, затова кешираме изчисления резултат. За по-лесно извикване предоставяме и друг <T>универсален метод SizeOf.

В кода по-долу го използваме, за да изведем броя байтове на две структури и типове с еднакво определение на полето. В следващата статия ще получим допълнително пълното двоично съдържание на инстанцията в паметта въз основа на изчисления брой байтове, така че останете на линия.

Оригинален линк:Входът към хиперлинк е видим.




Предишен:Фронтенд рамката учи проекта Component-Party с отворен код
Следващ:MinIO съхранение (iii) Копиране-качване (миграция) на локални файлове към minio bucket
 Хазяин| Публикувано на 27.08.2025 09:33:22 |
C# колекцията вмъква 10 000 парчета данни, които заемат паметта




Код:


Отричане:
Целият софтуер, програмни материали или статии, публикувани от Code Farmer Network, са само за учебни и изследователски цели; Горното съдържание не трябва да се използва за търговски или незаконни цели, в противен случай потребителите ще понесат всички последствия. Информацията на този сайт идва от интернет, а споровете за авторски права нямат нищо общо с този сайт. Трябва напълно да изтриете горното съдържание от компютъра си в рамките на 24 часа след изтеглянето. Ако ви харесва програмата, моля, подкрепете оригинален софтуер, купете регистрация и получете по-добри услуги. Ако има нарушение, моля, свържете се с нас по имейл.

Mail To:help@itsvse.com