Яка різниця між типом посилання та типом значення у c #?


100

Якийсь хлопець задав мені це питання пару місяців тому, і я не міг детально пояснити це. Яка різниця між типом посилання та типом значення у C #?

Я знаю , що типи значень int, bool, floatі т.д. , і посилальні типи delegate, interfaceі т.д. Або це не так, теж?

Чи можете ви мені це пояснити професійно?


3
Як невелика примітка, я думаю, що питання задається про C #, але насправді йдеться про C # + .NET. Ви не можете проаналізувати C # без аналізу .NET. Я не буду міняти це питання, тому що можна проаналізувати деякі моменти аналізу одного, не аналізуючи іншого (ітератори та закриття, я
дивлюсь

@xanatos - це найбільш доречно запитання про CLI, який об'єднує C #, VB.Net і, Net. Там повинен бути тег для CLI, але CLI береться за щось інше. Є CLR, але це реалізація, а не стандарт.
користувач34660

Відповіді:


172

Ваші приклади трохи дивно , тому що в той час int, boolі floatпевні типів, інтерфейси і делегати види типу - так само , як structі enumє видами типів значень.

Я написав лист на пояснення посилальних типів і типів значень в цій статті . Я буду радий розширити будь-які шматочки, які вам заплутаються.

Версія "TL; DR" - це продумати значення змінної / вираження певного типу. Для типу значення цінністю є сама інформація. Для типу посилання значення - це посилання, яке може бути нульовим або може бути способом навігації до об'єкта, що містить інформацію.

Наприклад, подумайте про змінну як про папір. На ній може бути написано значення "5" або "помилково", але мій будинок не міг ... він повинен був мати вказівки до мого будинку. Ці вказівки є еквівалентом посилання. Зокрема, двоє людей могли мати різні аркуші паперу, що містять однакові вказівки до мого будинку - і якщо одна людина дотримувалася цих вказівок і пофарбувала мій будинок червоним кольором, то друга людина побачила б і це. Якби вони обоє просто мали окремі фотографії мого будинку на папері, то одна людина, яка забарвлює їхній папір, взагалі не змінила б паперу іншої людини.


2
Важливо відзначити, що існує три різних основних типи семантики, що може запропонувати річ: незмінна семантика, семантика змінного значення та змінна семантика еталонів. Концептуально тип семантики, яку реалізує річ, є ортогональним щодо того, чи зберігається вона як окремий об'єкт купи або змінної / поля (структура). На практиці, хоча структури, які не відкривають свої поля, можуть реалізовувати будь-який вид семантики, той факт, що .net дозволяє нерозбірливий обмін посиланням купи, означає, що об’єкти купи не можуть реалізувати семантику змінних значень.
supercat

Я цього не отримав - while int, bool and float are specific types, interfaces and delegates are kinds of type - just like struct and enum are kinds of value types. Що ви маєте на увазі під int, bool є конкретними типами? Все в C #, наприклад, int, bool, float, клас, інтерфейс, делегат - це тип (тип даних, щоб бути точним). Типи даних відокремлюються як "Тип довідки" та "Тип значення" у C #. Тоді чому ви говорите ІНТ типу специфічний , але інтерфейс являє собою вид типу?
RBT

2
@RBT: типи даних не просто поділяються на "тип посилання" та "тип значення". Вони також розділені на "клас, структура, перерахунок, делегат, інтерфейс". intє структура, stringклас, Actionделегат і т. д. Ваш список "int, bool, float, клас, інтерфейс, делегат" - це список, що містить різні речі, так само як "10, int" список, що містить різні речі.
Джон Скіт

@JonSkeet Можливо, відповідь у цьому дописі є дещо оманливою.
RBT

@RBT: Я б сказав, що це дещо погано сформульовано, але не жахливо.
Джон Скіт

26

Тип значення:

Зберігає деяке значення, а не адреси пам'яті

Приклад:

Структуру

Зберігання:

TL; DR : значення змінної зберігається там, де вона скасована. Наприклад, локальні змінні живуть у стеку, але, коли вони оголошені всередині класу як члена, вони живуть на купі, щільно поєднаній з класом, в якому оголошено.
Довше : Типи значень зберігаються там, де вони оголошені. Напр .: значення int'у функції як локальної змінної зберігатиметься в стеці, тоді як intзначення' s, оголошене як член класу, зберігатиметься в купі з класом, в якому задекларовано. Тип значення на клас має тип життя, який точно такий же, як і клас, декларований у ньому, і не вимагає майже жодної роботи сміттєзбірника. Хоча це складніше, я б посилався на книгу @ C JonSkeet " C # In Dubth "Пам'ять у .NET "для більш короткого пояснення.

Переваги:

Тип значення не потребує додаткового збору сміття. Він отримує сміття, зібране разом з екземпляром, в якому він живе. Локальні змінні методи очищаються після відпустки методу.

Недоліки:

  1. Коли великий набір значень передається методу, приймаюча змінна фактично копіює, тому в пам'яті є два зайвих значення.

  2. Оскільки заняття пропущено. Це втрачає всі вигоди

Тип довідки:

Зберігає адресу пам'яті значення, яке не є значенням

Приклад:

Клас

Зберігання:

Зберігається на купі

Переваги:

  1. Коли ви передаєте посилання на змінну методу, і він змінюється, він дійсно змінює вихідне значення, тоді як у типах значень береться копія даної змінної, і це значення змінюється.

  2. Коли розмір змінної більший, тип посилання є хорошим

  3. Оскільки класи відносяться до змінних типів опорного типу, вони надають можливість повторного використання, тим самим виграючи об'єктно-орієнтоване програмування

Недоліки:

Більше посилань на роботу при розподілі та перенаправлення при зчитуванні перевантаження value.extra для сміттєзбірника


5
Не обов'язково вірно, що типи посилань зберігаються в купі, а типи значень зберігаються в стеку. Прочитайте yoda.arachsys.com/csharp/memory.html, якщо хочете дізнатися більше.
Рис

1
У цій відповіді багато непорозумінь. Прочитайте CLR Jeff Richters через C #. Типи значень зберігаються у стеці ниток і не підлягають збору сміття (GC) - вони не мають нічого спільного з GC. Типи довідок зберігаються в керованій купі і тому підлягають GC. Якщо тип Ref має кореневу посилання, він не може бути зібраний і просунутий поколіннями 0, 1 і 2. Якщо він не має кореневого посилання, він може бути зібраним сміттям, і він проходить цей процес під назвою Воскресіння, де він вбивають і повертають до життя, а потім остаточно збирають.
Джеремі Томпсон

13

Мені було простіше зрозуміти різницю цих двох, якщо ти знаєш, як комп'ютер розподіляє речі в пам'яті і знаєш, що таке покажчик.

Посилання, як правило, пов'язане з покажчиком. Значення адреси пам'яті, де перебуває ваша змінна, фактично містить іншу пам'ять фактичного об'єкта в іншому місці пам'яті.

Приклад, який я збираюсь навести, є надто спрощеним, тому візьміть його із зерном солі.

Уявіть, що пам'ять комп’ютера - це купа поштових скриньок поспіль (починаючи з / від Box 0001 до PO Box n), які можуть вмістити щось всередині неї. Якщо поштові скриньки не роблять це за вас, спробуйте хештеб, словник або масив чи щось подібне.

Таким чином, коли ви робите щось на кшталт:

var a = "Привіт";

комп'ютер зробить наступне:

  1. виділіть пам'ять (скажімо, починаючи з місця пам'яті 1000 на 5 байт) і поставте H (на 1000), e (на 1001), l (на 1002), l (на 1003) і o (на 1004).
  2. виділити десь у пам'яті (скажімо, у місці 0500) і призначити її змінною a.
    Так що це як псевдонім (0500 - це).
  3. призначте значення в цьому місці пам'яті (0500) до 1000 (саме там в пам'яті починається рядок Hello. Таким чином, змінна a містить посилання на фактичне місце початкової пам'яті рядка "Hello".

Тип значення буде містити фактичну річ у своїй пам'яті.

Таким чином, коли ви робите щось на кшталт:

var a = 1;

комп'ютер зробить наступне:

  1. виділіть місце пам'яті, скажімо, на 0500 та призначте його змінній a (та сама псевдонім)
  2. помістіть у нього значення 1 (у місці пам'яті 0500).
    Зауважте, що ми не виділяємо додаткову пам’ять для утримання фактичного значення (1). Таким чином, a фактично містить фактичне значення, і тому його називають типом значення.

1
Можливо, вас зацікавлять blogs.msdn.com/b/ericlippert/archive/2009/02/17/…
Джон Скіт

@ Jon, Що ж, таке недійсне, що я говорив, LOL. Але, як я вже сказав, це дуже спрощено, щоб отримати розуміння між двома типами, що в моєму випадку я вважав корисним. Принаймні, так я це намалював у своєму розумі :).
Джиммі Чандра

8

Це з моєї посади з іншого форуму, близько двох років тому. Незважаючи на те, що мова є vb.net (на відміну від C #), поняття типу "значення" та "еталон" є однаковими для всієї .net, і приклади все ще є.

Важливо також пам’ятати, що всередині .net ВСІ типи технічно походять від базового типу Object. Типи значень покликані поводитись як такі, але врешті-решт вони також успадковують функціональність базового типу Object.

A. Типи значень - це лише те, що вони представляють окрему область пам'яті, де зберігається дискретна VALUE. Типи значень мають фіксований об'єм пам'яті і зберігаються в стеці, що представляє собою сукупність адрес фіксованого розміру.

Коли ви робите таку заяву:

Dim A as Integer
DIm B as Integer

A = 3
B = A 

Ви зробили наступне:

  1. Створено 2 простору в пам'яті, достатніх для вміщення 32-бітових цілих значень.
  2. Розміщується значення 3 у виділенні пам'яті, призначеному A
  3. Розміщують значення 3 у виділенні пам'яті, призначеному B, присвоюючи йому те саме значення, що і у A.

Значення кожної змінної існує дискретно у кожному місці пам'яті.

B. Довідкові типи можуть бути різного розміру. Тому їх не можна зберігати у "Стек" (пам'ятаєте, стек - це набір розподілу пам'яті фіксованого розміру?). Вони зберігаються в "Керованій купі". Покажчики (або "посилання") на кожен елемент керованої купи зберігаються в стеці (як адреса). Ваш код використовує ці вказівники у стеку для доступу до об'єктів, що зберігаються в керованій купі. Отже, коли ваш код використовує посилання-змінну, він фактично використовує покажчик (або "адресу" на місце пам'яті в керованій купі).

Скажімо, ви створили клас під назвою clsPerson із рядком властивості Person.Name

У цьому випадку, коли ви робите заяву на зразок цієї:

Dim p1 As clsPerson
p1 = New clsPerson
p1.Name = "Jim Morrison"

Dim p2 As Person

p2 = p1

У випадку вище, властивість p1.Name поверне "Джим Моррісон", як і слід було очікувати. Властивість p2.Name також ТАКОЖ поверне "Джим Моррісон", як би ви інтуїтивно очікували. Я вважаю, що і p1, і p2 являють собою чіткі адреси стека. Однак тепер, коли ви призначили p2 значення p1, і p1, і p2 вказують на ІДНЕ МІСЦЕ на керованій купі.

Тепер перегляньте цю ситуацію:

Dim p1 As clsPerson
Dim p2 As clsPerson

p1 = New clsPerson
p1.Name = "Jim Morrison"

p2 = p1

p2.Name = "Janis Joplin"

У цій ситуації ви створили один новий екземпляр класу person на керованій купі з вказівником p1 на Стек, який посилається на об'єкт, і знову присвоїли властивості Name об'єкта об'єкта значення "Джим Моррісон". Далі ви створили інший вказівник p2 в Стек і вказали його на ту саму адресу в керованій купі, на яку посилається p1 (коли ви зробили призначення p2 = p1).

Ось іде поворот. Коли ви присвоюєте властивості Name p2 значення "Janis Joplin", ви змінюєте властивість Name для об'єкта, ПОЯСНЕНО обома p1 та p2, таким чином, якщо ви застосували такий код:

MsgBox(P1.Name)
'Will return "Janis Joplin"

MsgBox(p2.Name)
'will ALSO return "Janis Joplin"Because both variables (Pointers on the Stack) reference the SAME OBJECT in memory (an Address on the Managed Heap). 

Це мало сенс?

Остання. Якщо ви робите це:

DIm p1 As New clsPerson
Dim p2 As New clsPerson

p1.Name = "Jim Morrison"
p2.Name = "Janis Joplin"

Тепер у вас є два чіткі особисті об'єкти. Однак хвилини, коли ти знову це зробиш:

p2 = p1

Тепер ви обох повернули на "Джима Моррісона". (Я не точно впевнений, що сталося з Об'єктом на Купі, на який посилається p2. Я думаю, що він зараз вийшов із сфери застосування. Це одна з тих областей, де сподіваюся, що хтось може встановити мене прямо.). -EDIT: Я вірю, саме тому ви встановите p2 = Нічого АБО p2 = Новий clsPerson перед тим, як зробити нове завдання.

Ще раз, якщо ви зробите це:

p2.Name = "Jimi Hendrix"

MsgBox(p1.Name)
MsgBox(p2.Name)

Обидва msgBoxes тепер повернуть "Jimi Hendrix"

Це може бути трохи заплутаним, і я скажу останній раз, можливо, деякі деталі помиляються.

Удачі, і сподіваємось, інші, хто знають краще за мене, прийдуть, щоб допомогти прояснити щось із цього. . .


Я не знаю, чому ви не отримали жодного голосу. Гарна відповідь, допомогла мені зрозуміти чіткими, простими прикладами.
Гаррі

Що стосується поняття Value Type vs. Reference type, то є єдиними у всій .net, вони фактично визначені в специфікації Common Language Infrastructure (CLI), стандарт Ecma 335 (також стандарт ISO). Це стандарт для стандартної частини .Net. Стандарт Ecma 334 (також стандарт ISO) є мовою C #, і в ньому чітко зазначено, що C # реалізації повинні або покладатися на CLI, або підтримувати альтернативний спосіб отримання мінімальних функцій CLI, необхідних для цього стандарту C # . Однак VB.Net не є стандартом, він є власником Microsoft.
користувач34660

5

тип даних значення та тип базових даних

1) значення (містить дані безпосередньо), але посилання (відноситься до даних)

2) за значенням (кожна змінна має свою копію), але
за посиланням (більше, ніж змінна може стосуватися деяких об'єктів)

3) за значенням (змінна операція не може впливати на іншу змінну), але за посиланням (змінна може впливати на інші)

4) типами значень є (int, bool, float), а тип посилання - (масив, об'єкти класу, рядок)


2

Тип значення:

  • Фіксований об'єм пам'яті.

  • Зберігається в пам'яті стека.

  • Зберігає фактичне значення.

    Вих. int, char, bool тощо ...

Тип довідки:

  • Не фіксована пам'ять.

  • Зберігається в пам'яті Heap.

  • Зберігає адресу пам'яті фактичного значення.

    Вих. рядок, масив, клас тощо ...


1

"Змінні, що базуються на типах значень, безпосередньо містять значення. Призначення однієї змінної типу значення іншої копіює міститься значення. Це відрізняється від присвоєння змінним типу опорного типу, що копіює посилання на об'єкт, але не на сам об'єкт." з бібліотеки Microsoft.

Ви можете знайти більш повну відповідь тут і тут .


1
Мені не подобається це пояснення, тому що це звучить як присвоєння працює по-різному для типів посилань та типів значень. Це не так. В обох випадках це значення змінної «target» дорівнює виразу - значення копіюється. Різниця є в тому , що значення - для посилальних типів, значення , яке копіюється є посиланням. Це все ще значення змінної.
Джон Скіт

Я згоден з вами, і я вже знав, що це може бути інакше, як ви можете прочитати в цій статті . Але я просто переосмислюю посібник Microsoft щодо цієї теми, а також того, як ви зазвичай читаєте в книгах. Будь ласка, не звинувачуйте мене! :)
Лукас С.

О, звичайно ... тут є багато біт документації MSDN, де винна помилка :)
Джон Скіт

1

Іноді пояснення не допоможуть особливо початківцям. Ви можете уявити тип значення як файл даних, а тип посилання - як ярлик до файлу.

Отже, якщо ви копіюєте змінну посилання, ви копіюєте лише посилання / покажчик на реальні дані десь у пам'яті. Якщо ви копіюєте тип значення, ви дійсно клонуєте дані в пам'ять.


0

Це, мабуть, неправильно в езотеричних способах, але, щоб спростити це:

Типи значень - це значення, які зазвичай передаються "за значенням" (так що їх копіювання). Типи посилань передаються "за посиланням" (так даючи вказівник на вихідне значення). Немає жодної гарантії стандартом .NET ECMA щодо збереження цих "речей". Ви можете створити реалізацію .NET, яка не є бездоганною, або ту, яка є бездоганною (друге було б дуже складним, але ви, ймовірно, могли, використовуючи волокна та багато стеків)

Структури - це значення типу (int, bool ... - це структури, або принаймні імітуються як ...), класи - тип посилань.

Типи значень походять від System.ValueType. Довідковий тип сходить із System.Object.

Тепер .. Зрештою, у вас є Value Value, "посилання на об'єкти" та посилання (у C ++ їх би називали вказівниками на об'єкти. У .NET вони непрозорі. Ми не знаємо, що вони. З нашої точки зору, вони є "ручками" до об'єкта). Ці тривалості схожі на типи значень (передаються копією). Таким чином, об'єкт складається з об'єкта (еталонний тип) і до нуля або більше посилань на нього (які схожі на типи значень). Коли є нульові посилання, GC, ймовірно, збирає його.

Загалом (у реалізації .NET) тип значень може переходити на стек (якщо вони локальні поля) або на купу (якщо вони поля класу, якщо вони є змінними у функції ітератора, якщо вони є змінними, на які посилається закриття, якщо вони змінні у функції асинхронізації (використовуючи новіший Async CTP) ...). Посилане значення може перейти лише до купи. У посиланнях використовуються ті самі правила, що і типи значень.

У випадках типу Value, які переходять на купу, оскільки вони перебувають у функції ітератора, функції асинхронізації або на яку посилається закриття, якщо ви дивитесь складений файл, ви побачите, що компілятор створив клас для розміщення цих змінних , і клас будується під час виклику функції.

Зараз я не знаю, як писати довгі речі, і в мене є кращі речі, які потрібно робити в житті. Якщо ви хочете "точну" "академічну" "правильну" версію, прочитайте ЦЕ:

http://blogs.msdn.com/b/ericlippert/archive/2010/09/30/the-truth-about-value-types.aspx

Минув 15 хвилин! Це краще, ніж версії msdn, тому що це стисла стаття "готова до використання".


1
Це неправильно більш ніж езотеричними способами. Я б сказав, що це принципово неправильно, оскільки значення еталонного типу все ще передаються за значенням; це просто те, що значення є посиланням, а не об'єктом. Дивіться pobox.com/~skeet/csharp/parameters.html . Так, і локальні змінні можуть також опинитися на купі, наприклад, якщо вони захоплені або є частиною ітераторського блоку.
Джон Скіт

Блоки ітераторів перетворюються на класи, тому "позаду" вони є "полями класу". Те саме для закриття. Так ... я забув написати різницю між "покажчиком" (посиланням) та "
вказаним

@xanatos: Звичайно, вони поля класу після компіляції - але вони все ще локальні змінні у вихідному коді. Я також не назвав би посилання самими "типами цінності" - я думаю, що я знаю, звідки ви беретеся, але не думаю, що таким чином забруднювати води таким чином не варто.
Джон Скіт

@jon Так ... Вони третього типу, тому що вказівники "непрозорі" в .net, і вони не походять від ValueType. Але вони більше схожі на типи значень, ніж на посилання. Ви можете їх "переосмислити" та "вимкнути". Мені довелося замульчувати води, тому що "комусь" довелося виконувати роботу ітераторів.
xanatos

Переглядаючи статтю, на яку я зараз вказую, я виявив: "Є три види значень: (1) екземпляри типів значень, (2) екземпляри типів посилань та (3) посилання. (Кодом в C # не можна маніпулювати екземпляри типів посилань безпосередньо; це завжди робиться через посилання. У небезпечному коді типи вказівників розглядаються як типи значень для визначення вимог зберігання їх значень. ) ".
xanatos

0

Найпростіший спосіб думати про еталонні типи - вважати їх "ідентифікаторами об'єктів"; Єдине, що можна зробити з ідентифікатором об’єкта, - це створити один, скопіювати один, запитати або маніпулювати типом одного або порівняти два для рівності. Спроба зробити що-небудь інше з ідентифікатором об’єкта буде розглядатися як скорочення для виконання зазначеної дії з об'єктом, на який посилається цей ідентифікатор.

Припустимо, у мене є дві змінні X і Y типу Car - еталонний тип. У Y трапляється "ідентифікатор об'єкта № 19531". Якщо я скажу "X = Y", це призведе до того, що X утримує "ідентифікатор об'єкта № 19531". Зауважте, що ні X, ні Y не мають автомобіля. Автомобіль, інакше відомий як "ідентифікатор об'єкта № 19531", зберігається в іншому місці. Коли я скопіював Y в X, я лише скопіював ідентифікаційний номер. Тепер припустимо, що я скажу X.Color = Colors.Blue. Таке твердження буде розглядатися як інструкція шукати "ідентифікатор об'єкта № 19531" і пофарбувати його в синій колір. Зауважте, що хоча X і Y зараз посилаються на синій автомобіль, а не на жовтий, заява насправді не впливає на X чи Y, оскільки обидва досі посилаються на "об'єкт ідентифікатор № 19531", який все ще є тим же автомобілем, що і він завжди був.


0

Змінні типи та довідкове значення легко застосовувати і добре застосовувати до доменної моделі, полегшують процес розробки.

Щоб видалити будь-який міф навколо суми "типу цінності", я прокоментую, як це обробляється на платформі. NET, конкретно в C # (CSharp), коли викликається APIS та надсилає параметри за значенням, посиланням, у наших методах та функціях, і як зробити правильну обробку проходів цих значень.

Читайте цю статтю Значення та довідник змінної типу в C #


На жаль, це лише питання англійською мовою, на жаль = \. Дякуємо, що спробували відповісти. Будь ласка, створіть повну відповідь із посиланнями лише як посібники (але не як повну стійку відповідь). Будь ласка, подивіться, як відповісти .
Джессі

0

Припустимо, vце вираження / змінна типу типу та rє виразом / змінною опорного типу

    x = v  
    update(v)  //x will not change value. x stores the old value of v

    x = r 
    update(r)  //x now refers to the updated r. x only stored a link to r, 
               //and r can change but the link to it doesn't .

Отже, змінна типу значення зберігає фактичне значення (5 або "h"). Переменний тип посилання зберігає лише посилання на метафоричне поле, де є значення.


0

Перш ніж пояснити різні типи даних, доступні в C #, важливо згадати, що C # є сильно набраною мовою. Це означає, що кожна змінна, константа, параметр вводу, тип повернення і взагалі кожен вираз, який оцінює значення, має тип.

Кожен тип містить інформацію, яка буде вбудована компілятором у виконуваний файл у вигляді метаданих, які будуть використовуватися загальним мовним часом виконання (CLR) для гарантування безпеки типу, коли він виділяє та відновлює пам'ять.

Якщо ви хочете знати, скільки пам'яті виділяє певний тип, ви можете використовувати оператор sizeof наступним чином:

static void Main()
{
    var size = sizeof(int);
    Console.WriteLine($"int size:{size}");
    size = sizeof(bool);
    Console.WriteLine($"bool size:{size}");
    size = sizeof(double);
    Console.WriteLine($"double size:{size}");
    size = sizeof(char);
    Console.WriteLine($"char size:{size}");
}

Вихідні дані покажуть кількість байтів, виділених кожною змінною.

int size:4
bool size:1
double size:8
char size:2

Інформація, що стосується кожного типу, є:

  • Необхідний простір для зберігання.
  • Максимальні та мінімальні значення. Наприклад, тип Int32 приймає значення між 2147483648 і 2147483647.
  • Базовий тип, який він успадковує.
  • Місце, де під час виконання буде виділена пам'ять для змінних.
  • Види операцій, які дозволені.
  • Учасники (методи, поля, події тощо) містять тип. Наприклад, якщо ми перевіримо визначення типу int, то знайдемо таку структуру та членів:

    namespace System
    {
        [ComVisible(true)]
        public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<Int32>, IEquatable<Int32>
        {      
            public const Int32 MaxValue = 2147483647;     
            public const Int32 MinValue = -2147483648;
            public static Int32 Parse(string s, NumberStyles style, IFormatProvider provider);    
            ... 
        }  
    }

Управління пам'яттю Коли в операційній системі запущено декілька процесів і об'єм оперативної пам’яті недостатньо, щоб утримати її все, операційна система відображає частини жорсткого диска з оперативною пам’яттю і починає зберігати дані на жорсткому диску. Операційна система використовуватиме, ніж конкретні таблиці, де віртуальні адреси відображаються на їх кореспондентські фізичні адреси для виконання запиту. Ця можливість управління пам'яттю називається віртуальною пам'яттю.

У кожному процесі наявна віртуальна пам'ять організована в наступних 6 розділах, але для актуальності цієї теми ми зупинимося лише на стеці та купі.

Стек Стек являє собою структуру даних LIFO (останній, перший), залежно від розміру операційної системи (за замовчуванням - резерв 1MB для систем ARM, x86 та x64, в той час як Linux резервує від 2 МБ до 8 МБ, залежно від цього версія).

Цим розділом пам'яті автоматично керує процесор. Кожен раз, коли функція оголошує нову змінну, компілятор виділяє новий блок пам'яті, такий же великий, як і її розмір на стеку, а коли функція закінчена, блок пам'яті для змінної переміщується.

Купа Ця область пам'яті не управляється автоматично процесором, і її розмір більший, ніж стек. Після виклику нового ключового слова компілятор починає шукати перший вільний блок пам'яті, який відповідає розміру запиту. і коли він знаходить його, він позначається як зарезервований за допомогою вбудованої функції C malloc () та повертає вказівник на це місце. Можливо також розмістити блок пам'яті за допомогою вбудованої функції С (free). Цей механізм викликає фрагментацію пам’яті і має використовувати вказівники для доступу до правого блоку пам’яті, він повільніше, ніж стек для виконання операцій читання / запису.

Спеціальні та вбудовані типи Хоча C # пропонує стандартний набір вбудованих типів, що представляють цілі числа, булеві, текстові символи тощо, ви можете використовувати такі структури, як структура, клас, інтерфейс та enum для створення власних типів.

Приклад користувальницького типу за допомогою структури constru:

struct Point
{
    public int X;
    public int Y;
};

Значення та довідкові типи Ми можемо класифікувати тип C # у такі категорії:

  • Типи значення
  • Довідкові типи

Типи значення Типи значень походять від класу System.ValueType і змінні цього типу містять свої значення в межах розподілу пам'яті в стеку. Дві категорії типів цінності - структура та перерахунок.

Наступний приклад показує член булевого типу. Як видно, явного посилання на клас System.ValueType немає, це відбувається тому, що цей клас успадковується структура.

namespace System
{
    [ComVisible(true)]
    public struct Boolean : IComparable, IConvertible, IComparable<Boolean>, IEquatable<Boolean>
    {
        public static readonly string TrueString;
        public static readonly string FalseString;
        public static Boolean Parse(string value);
        ...
    }
}

Типи довідок З іншого боку, типи посилань містять не фактичні дані, що зберігаються у змінній, а адресу пам'яті в купі, де зберігається значення. Категорії типів посилань - це класи, делегати, масиви та інтерфейси.

Під час виконання, коли оголошена змінна тип посилання, вона містить значення null до тих пір, поки об’єкт, створений за допомогою нових ключових слів, не буде присвоєний йому.

Наступний приклад показує членів списку загального типу.

namespace System.Collections.Generic
{
    [DebuggerDisplay("Count = {Count}")]
    [DebuggerTypeProxy(typeof(Generic.Mscorlib_CollectionDebugView<>))]
    [DefaultMember("Item")]
    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {
        ...
        public T this[int index] { get; set; }
        public int Count { get; }
        public int Capacity { get; set; }
        public void Add(T item);
        public void AddRange(IEnumerable<T> collection);
        ...
    }
}

Якщо ви хочете дізнатися адресу пам'яті конкретного об'єкта, клас System.Runtime.InteropServices забезпечує спосіб доступу до керованих об'єктів з некерованої пам'яті. У наступному прикладі ми будемо використовувати статичний метод GCHandle.Alloc (), щоб виділити ручку рядку, а потім метод AddrOfPinnedObject для отримання його адреси.

string s1 = "Hello World";
GCHandle gch = GCHandle.Alloc(s1, GCHandleType.Pinned);
IntPtr pObj = gch.AddrOfPinnedObject();
Console.WriteLine($"Memory address:{pObj.ToString()}");

Вихід буде

Memory address:39723832

Посилання Офіційна документація: https://docs.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=vs-2019


-1

Існує багато невеликих деталей про відмінності між типами значень та типовими типами, які чітко викладені стандартом, а деякі з них нелегкі для розуміння, особливо для початківців.

Див. Стандарт 33 ECMA , Загальна мовна інфраструктура (CLI) . CLI також стандартизований ISO. Я б надавав посилання, але для ECMA ми повинні завантажити PDF-файл, і це посилання залежить від номера версії. Стандарти ISO коштують грошей.

Одна відмінність полягає в тому, що типи значень можуть бути розміщені в полі, але типи посилань зазвичай не можуть бути. Винятки є, але вони досить технічні.

Типи значень не можуть мати конструкторів екземплярів або фіналізаторів без параметрів, і вони не можуть посилатися на себе. Звернення до себе означає, наприклад, що якщо існує тип значення Node, то член Node не може бути Вузлом . Я думаю, що в специфікаціях є й інші вимоги / обмеження, але якщо так, то вони збираються не в одному місці.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.