2016-07-27 3 views
32

Я пытаюсь узнать, как C# управляет памятью. Я застрял на статических элементах, я читал многочисленные блоги и статьи по этому вопросу, но я не могу найти вполне удовлетворительный ответ.Где хранятся все статические элементы?

Давайте определим блок кода, чтобы найти ответ.

class myClass 
{ 
    static string myStr = "String Data"; 
    static int myInt = 12; 
} 

Прежде чем вы, ребята, поделитесь своим ответом, позвольте мне поделиться своими выводами, которые я знаю об этой теме. Не стесняйтесь соглашаться или не соглашаться и помогать мне найти правильный ответ.

  • Static предназначен для всей жизни.
  • Статический ссылочный тип (myStr), будет включен в кучу, на всю жизнь.
  • Статический тип значения (myInt), будет идти на стек, для жизни.

Что меня смущает, некоторые ответы, которые я нашел в Интернете, по этому вопросу.

Путаница Номер 1:

При запуске программы он загружает все связанные сборки в AppDomain. Когда сборка загружается, вызывается все статические конструкторы, включая статические поля. Они будут жить там, и единственный способ их разгрузить - выгрузить AppDomain.

В приведенных выше строках указано, что все статические элементы хранятся в AppDomain. Тогда почему все в Интернете говорят, что элементы «Статические» хранятся в куче/стеке?

Путаница Номер 2:

Каждая статическая переменная хранится в куче, независимо от того, является ли это объявленная внутри ссылочного типа или типа значения.

Если каждая статическая переменная хранится в куче. Тогда почему некоторые люди говорят, что статическая переменная типа значения хранится в стеке?

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

+15

Люди могут смутить себя, перетаскивая понятия «стопка» и «куча» в первую очередь. Эти понятия не полезны сами по себе, если все, о чем вы хотите знать, - это время жизни объекта или область декларации, которые являются гораздо более релевантными понятиями на C#. Сбор мусора означает, что в 95% случаев вам нужно только заботиться о том, жив или нет объект, а объект, на который ссылается поле 'static', жив до тех пор, пока загружается класс. (Что касается того, когда он создан, это более сложная тема.) Конечно, это не ответ. –

+1

Потому что они ошибаются. Они знают, что переменные типа значения _local_ хранятся в стеке (когда на самом деле все локальные переменные хранятся в стеке. Путаница заключается в том, что для ссылочного типа переменная является ссылкой, а не объектом). Статические переменные похожи на члены объекта 'Type', а' Type' не является типом значения. (Конечно, в отличие от Java, у C# на самом деле нет типа 'Type ', чтобы было понятнее, что каждый' Type' является _different_-типом и имеет разные члены) – Random832

+6

@ Random832: Не все локальные переменные находятся в стеке. Закрытые местные жители не находятся в стеке. Локали в блоках итератора не находятся в стеке. Локали в асинхронных методах не находятся в стеке. Зарегистрированные местные жители не находятся в стеке. Элитные местные жители не находятся в стеке. Не верьте, что местные жители идут в стек; это просто ложно. Местные жители называются locals *, потому что их имена имеют локальную область *, а не потому, что они хранятся в стеке. –

ответ

48

Прежде всего, обратите внимание, что все это деталь реализации. Единственное, что во время выполнения гарантии является:

  • Когда вы просите для статического поля, то есть
  • Статический конструктор выполняется в какой-то момент, прежде чем использовать тип

Это в значительной степени это , Все остальное является детальностью реализации - спецификация не заботится о стеке, куче или чем-то еще. Это зависит от реализации среды выполнения, и допустимая среда выполнения может помещать все в стек, если это того пожелает, или в кучу. И не забывайте регистры.

Теперь давайте посмотрим некоторые из заблуждений вы уже успели подобрать:

  • Static только для жизни - да. Он ничего не говорит о том, когда и где он хранится - просто, что он доступен, когда вы его просили. Соответствующая среда исполнения может свободно использовать любую память, которую она хочет, или даже никогда не загружать поля в памяти (например, сохраняя ее в изображении, которое уже находится в памяти).
  • Статик будет продолжать кучу на всю жизнь - Скорее всего, да. Но это не входит в спецификацию, и совместимая среда исполнения может хранить ее там, где она хочет, или вообще нигде, при условии соблюдения надлежащих гарантий. Кроме того, не забывайте, что «для жизни» означает «по крайней мере, для жизни AppDomain»; он может быть или не быть освобожден, когда домен будет выгружен.
  • Статический тип значения будет идти на стек, на время жизни - скорее всего, нет. Опять же, деталь реализации, но стек имеет совершенно другую семантику, чем то, что имеет смысл для статического значения. И следующий момент даст вам больше причин, почему:
  • Когда загружается assambly, вызываются все статические конструкторы, включая статические поля. - Нет. Нет такого требования, и такой гарантии нет. Если вы полагаетесь на это, ваша программа будет ломаться (и я видел это много раз раньше). Опять же, деталь реализации, но в текущих реализациях MSCLR, статика, как правило, выделяется в кучу своей, а некоторое время до того, как тип, который они определены, необходим. Вы можете легко увидеть это, если вы создадите исключение в статическом конструкторе - оно вызовет TypeLoadException, скорее всего, в методе, который сначала ссылается на тип (само собой разумеется, это может привести к сложной отладке статики).
  • Типы ссылок идут в кучу, типы значений идут в стек. - Нет. Это путает механизм с семантикой.Единственная разница между ними - их семантика - все остальное зависит от реализации. Если среда выполнения может сохранять ссылочную семантику для ссылочных типов в стеке, это совершенно верно. И даже при текущих моделях MSCLR значения типов сохраняются в куче все время - всякий раз, когда они помещаются в коробку, или, например, члены ссылочного типа.

Некоторые люди могут быть смущены. Некоторые не понимают разницу между контрактом и практическими реализациями. Некоторые просто не знают, о чем они говорят. Хотелось бы, чтобы был простой способ узнать, что есть, но нет. Если вы сомневаетесь, вы можете перейти к спецификациям C#/CLR, но это только говорит о контракте, а не о практической реальности.

Весь смысл управляемой памяти в том, что вы не должны заботиться об этих деталях реализации. Конечно, как и любая абстракция, она течет - и имеет смысл знать, как это происходит на самом деле, вплоть до микроинструкций процессора, кэширования памяти и т. Д. Через все уровни и абстракции. Но это ничего не стоит rely on - реализация может измениться в любое время, и она имеет много раз в прошлом.

+0

Я согласен с вами в том, что все его детали реализации, которые могут меняться со временем. Поэтому я пришел к выводу, что AppDomain имеет свою собственную старую кучу. Которая управляет статическими элементами как значения, так и ссылочного типа. –

+0

@AliAsad Да, в основном. Он все еще рассматривается во время сбора мусора (он может иметь ссылки на объекты на других кучах), но фактически не собирается на практике. Также обратите внимание, что строки являются специальными - по умолчанию все литеральные строки интернированы, поэтому, если ваша статика имеет строковое значение, само значение, скорее всего, будет в еще одной куче (как правило, большой куче объекта). – Luaan

+0

@AliAsad А что касается контрактных материалов, статика в разных доменах приложений обязательно изолирована. Это не требует * объектов в разных кучах, но, безусловно, делает их удобными :) – Luaan

1

Существует экземпляр класса, созданного со всеми статическими членами, инициализированными.

Члены статических классов обычно хранятся в куче, члены типов значений обычно хранятся в стеке.

Это не обязательно так, вы можете прочитать блог this для получения дополнительной информации.

Это один из разработчиков языка C#, Эрик Липперт.

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

Это просто не указано в спецификации.

5

Всякий раз, когда процесс загружается в ОЗУ, можно сказать, что память грубо разделить на три зоны (в пределах этого процесса): Стек, Куча, и статический (который, в .NET, на самом деле специальная область внутри кучи , известная только как высокочастотная куча).

Статическая часть содержит «статические» переменные-члены и методы. Что такое точно статично? Эти методы и переменные, которые не нуждаются в экземпляр класса создаваемого определяются как статические

here Подробнее.

0

Каждая статическая переменная хранится в куче независимо от того, объявлена ​​ли она в ссылочном типе или типе значения. Всего всего один слот независимо от того, сколько экземпляров создано. (Там не обязательно должны быть экземпляры, созданные для того, чтобы один слот существовал.)

Кроме того, если статическая переменная выделена, она будет сохранена как часть Methodtable. Методические средства. Когда класс загружается впервые в приложении, отдельная память будет выделена в appdomain для переменных уровня класса и методов внутри класса. ,

Если статическая переменная является примитивным типом, она будет храниться как часть Methodtable. Если это ссылочный тип, он будет храниться внутри кучи, и ссылка будет сохранена в Methodtable.

+0

Спасибо. Звучит, каждый AppDomain имеет свою собственную старую кучу. Которая управляет статическими элементами как значения, так и ссылочного типа. Поправьте меня если я ошибаюсь. –

+1

Да Вы абсолютно правы – Lakhtey

Смежные вопросы