Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
12
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

3.8.1Полные имена

Каждое пространство имен и тип имеют полные имена, уникально идентифицирующие пространство имен или тип среди других пространств имен и типов. Значение полного имени пространства имен или типа N определяется следующим образом.

  • Если N является членом глобального пространства имен, его полное имя N.

  • В противном случае его полное имя S.N, где S — полное имя пространства имен или типа, в котором N объявлен.

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

В следующем примере представлено несколько объявлений пространств имен и типов вместе с соответствующими полными именами.

class A {} // A

namespace X // X { class B // X.B { class C {} // X.B.C }

namespace Y // X.Y { class D {} // X.Y.D } }

namespace X.Y // X.Y { class E {} // X.Y.E }

3.9Автоматическое управление памятью

C# развертывает автоматическое управление памятью, что освобождает разработчиков от ручного выделения и освобождения памяти, занятой объектами. Политики автоматического управления памятью реализованы в сборщике мусора. Далее представлен жизненный цикл объекта управления памятью.

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

  2. Если объект или его любая часть не могут быть вызваны посредством любой возможной продолжительности выполнения, отличной от выполнения деструкторов, объект считается неиспользуемым и становится доступным для деструкции. Компилятор C# и сборщик мусора могут анализировать код с целью определения того, какие ссылки на объект могут быть использованы в будущем. Например, если локальная переменная в области является единственной существующей ссылкой на объект, но на нее никогда не ссылались в любом возможном предложении выполнения, начиная с текущего момента выполнения в процедуре, сборщик мусора может (но не обязательно) посчитать данный объект неиспользуемым.

  3. После того, как объект становится доступным для деструкции, через некоторое указанное время выполняется деструктор (§10.13) (при наличии) для объекта. При отсутствии иных явных вызовов деструктор для объекта выполняется только один раз.

  4. Если после выполнения деструктора для объекта данный объект или любая его часть не доступны для любого продолжения выполнения, включая выполнение деструкторов, объект считается недоступным и становится доступным для коллекции.

  5. В итоге, через некоторое время после того, как объект стал доступным для коллекции, сборщик мусора очищает память, связанную с объектом.

Сборщик мусора хранит информацию об использовании объекта и использует ее для принятия решений управления памятью, например, где расположить в памяти новый созданный объект, когда следует переместить объект и когда объект больше не используется или недоступен.

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

Поведение сборщика мусора можно в некоторой степени контролировать посредством статических методов класса System.GC. Этот класс может использоваться для запроса выполнения сборки, выполнения деструкторов (или отмены выполнения) и т. п.

Так как сборщику мусора предоставляются широкие возможности в решении момента сборки объектов и выполнения деструкторов, соответствующая реализация может привести к результату, отличающемуся от представленного кода. Программа

using System;

class A { ~A() { Console.WriteLine("Destruct instance of A"); } }

class B { object Ref;

public B(object o) { Ref = o; }

~B() { Console.WriteLine("Destruct instance of B"); } }

class Test { static void Main() { B b = new B(new A()); b = null; GC.Collect(); GC.WaitForPendingFinalizers(); } }

приводит к созданию экземпляра класса A и экземпляра класса B. Данные объекты становятся доступны сборщику мусора, когда переменной b присваивается значение null, так как после этого доступ к ним невозможен посредством любого пользовательского кода. Результат может быть одним из следующих:

Destruct instance of A Destruct instance of B

или

Destruct instance of B Destruct instance of A

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

В особых случаях отличие между «доступен для деструкции» и «доступен для сборки» может быть очень важным. Например,

using System;

class A { ~A() { Console.WriteLine("Destruct instance of A"); }

public void F() { Console.WriteLine("A.F"); Test.RefA = this; } }

class B { public A Ref;

~B() { Console.WriteLine("Destruct instance of B"); Ref.F(); } }

class Test { public static A RefA; public static B RefB;

static void Main() { RefB = new B(); RefA = new A(); RefB.Ref = RefA; RefB = null; RefA = null;

// A and B now eligible for destruction GC.Collect(); GC.WaitForPendingFinalizers();

// B now eligible for collection, but A is not if (RefA != null) Console.WriteLine("RefA is not null"); } }

В вышеуказанной программе, если сборщик мусора выбирает выполнение деструктора A до деструктора B, то результат программы может быть следующим:

Destruct instance of A Destruct instance of B A.F RefA is not null

Обратите внимание, что, несмотря на то, что экземпляр A не был использован, а деструктор A был выполнен, методы A (в данном случае F) могут быть все равно вызваны из другого деструктора. Также обратите внимание, что выполнение деструктора может привести к тому, что объект станет снова доступен для использования из основной программы. В этом случае выполнение деструктора B привело к тому, что экземпляр A, который ранее не был использован, стал доступен из существующей ссылки Test.RefA. После вызова WaitForPendingFinalizers экземпляр B доступен для сборки, а экземпляр A недоступен для сборки из-за ссылки Test.RefA.

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

Альтернативой использованию деструкторов может служить реализация классом интерфейса System.IDisposable. Это позволит клиенту объекта определить момент освобождения ресурсов объекта, что обычно происходит путем вызова объекта в качестве ресурса с помощью оператора using (§8.13).

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]