2009-08-24 4 views
7

Здесь много людей смущены,Где CLR хранит статические классы?

Обычный класс хранит свои данные в куче справа? И ссылка (указатель) на стек.

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

Теперь в случае статических классов память не может быть очищена сборщиком мусора, поскольку в ней должна быть вся программа. И нет способа получить ссылку в первую очередь.

Итак, когда мы звоним в Консоль. Напишите, например? Где программа получает свою ссылку от (Где хранится ссылка на статический класс)? Или это просто называет это напрямую, но как?

+4

Я не понимаю какой-либо части этого вопроса. Что вы подразумеваете под «своей ценностью» и «ее ссылкой»? –

+0

Я ожидаю, что он говорит о том, как он отделяет исполняемый код от членов данных. –

+1

Среди других вопросов это «его». – jason

ответ

16

Я думаю, что вы путаете классы с где память живет с как память держится на. Когда вы создаете экземпляр нормального класса, память этого экземпляра живет в куче. A ссылка на этот экземпляр может находиться в объекте в куче (если вы установите переменную-член внутри другого экземпляра объекта); или переменной стека (если вы объявили переменную объекту внутри метода или передали его вызову функции), или он может быть в списке глобальных корней (если это статическая ссылка, например, ссылка Singleton).

Статический класс не может быть создан. Нет никакой ссылки на класс в любом месте (кроме информации о типе). Его методы - это просто функции, загружаемые в память, когда среда CLR загружает сборку. Вы можете создать делегат, который указывает на один из этих методов, но это также не делает ссылку на экземпляр класса. Это просто указатель на функцию.

Например, посмотрите на этот код:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static void Main(string[] args) 
{ 
    ObjectWrapper wrapper = new ObjectWrapper(); 
    ... 
} 

Главный метод создает экземпляр класса ObjectWrapper. Этот экземпляр живет в куче.

Внутри экземпляра ObjectWrapper есть экземпляр класса Object, который живет в куче. Ссылка на этот класс находится внутри экземпляра, поэтому, я думаю, вы могли бы считать ссылку «живущей в куче».

Теперь сравните это с помощью следующего кода:

class Singleton 
{ 
    static readonly instance = new Singleton(); 
} 

Экземпляр объекта Singleton живет в куче, тоже. Однако ссылка является статической ссылкой. Он поддерживается CLR в списке глобальных или «корневых» ссылок.

Теперь посмотрим на этот статический класс:

class ObjectWrapper 
{ 
    Object obj = new Object(); 
} 

static class HelperMethods 
{ 
    static int DoSomethingUseful(ObjectWrapper wrapper1) 
    { 
     ObjectWraper wrapper2 = wrapper1; 
     // code here 
    } 
} 

HelperMethods является статическим классом. Вы не можете создать экземпляр класса HelperMethods. В куче не может быть объектов этого класса. Однако в методе DoSomethingUseful он имеет две ссылки на экземпляр класса ObjectWrapper в стеке. Один передается, и один из них объявляется внутри метода.

+0

+1, наслаждался подробно. – user7116

+0

Что касается «корней», ознакомьтесь с этой статьей, которая объясняет алгоритм GC GC и разъясняет, как корни играют роль в GC. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx – felideon

+0

В этом ответе есть несколько моментов, которые не совсем точны. Во-первых, утверждение «Нет» ссылки на него в любом месте неверно. Ссылка на каждый тип, статический или другой, хранится в куче загрузчика. Вся система типов управляется в куче загрузчика со ссылками на типы и их элементы. Кроме того, «Этот класс никогда не будет потреблять память в куче» также неверен ... пока он не потребляет пространство кучи GC, он потребляет кучу кучи на куче загрузчика. Идея ссылки, просто являющаяся указателем, также неверна ... CLR использует много уровней косвенности. – jrista

6

Чтобы дать вам простой ответ, статические классы «хранятся» на так называемой кучке Loader.Кучи загрузчика - это специальные, не-GC исцеления, которые имеют чрезвычайно предсказуемые и строгие темпы роста. Когда приложение .NET запускается, на самом деле создается несколько AppDomains. В дополнение к основному домену приложений существуют системные и общие домены приложений, которые содержат пространства имен систем и mscorelib, специальные кучи (такие как кучи загрузчика) и сам CLR.

Для полного детального объяснения, прочитайте следующую MSDN Magazine статью:

Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects

Несмотря на то, от нескольких лет назад, она до сих пор применяется. (Тем не менее, я не могу сказать, сильно ли изменился .NET 4.0).