Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
В.NET используется автоматическое управление выделением и освобождением памяти. Менеджер кучи быстро выделяет память для вновь создаваемых объектов благодаря наличию указателя на начало непрерывного свободного пространства в куче. Если этот указатель приближается к границе кучи, и менеджер не может выделить память по очередному запросу, выполняется дорогостоящий процесс освобождения более не используемой памяти. Сборщик мусора находит ссылки на все используемые объекты, и перемещает их образы в куче к ее началу, модифицируя все адреса перемещаемых объектов в данных и в коде. Вся остальная часть кучи после последнего используемого объекта считается свободной.
Конечно,
• Недетерминированность
Момент начала сборки мусора заранее как правило не известен. Если объект связывает ценные ресурсы (открытые файлы, соединения с базой данных), то клиент должен явно вызвать метод Dispose, в котором объект должен реализовать освобождение упомянутых и других ценных ресурсов не дожидаясь начала работы сборщика мусора.
Если надежд на клиента мало, класс должен реализовать метод Finalize, в котором также должно выполняться освобождение ресурсов. В отличие от метода Dispose, метод Finalize вызывается автоматически во время сборки мусора до уничтожения объекта.
• Распределенная сборка мусора
Сборщик мусора не имеет доступа к удаленным объектам. Их освобождение регулируется другим механизмом, т. н. лизингом (leasing).
Последняя часть кода клиента демонстрирует применение механизма рефлексии. Цель — вывести на консоль сигнатуры всех методов, которые доступны через интерфейс IAudit. Заметим, что это будут не только все методы, реализованные в классе Account, но и все методы, реализованные в корневом классе System.Object, от которого неявно наследуют все классы в .NET, в том числе и класс Account.
Наследуемый метод GetType позволяет получить ссылку на объект типа Tуре, содержащий всю нужную информацию. Далее формируется массив всех доступных методов и в цикле на консоль выводится сигнатура каждого доступного метода.
Таким образом, механизм рефлексии предоставляет ту информацию, которая в рамках СОМ хранилась в IDL– файлах, в заголовочных файлах, в библиотеке типов.
Теперь рассмотрим вопросы компиляции и развертывания построенного приложения.
Важнейшее новшество в .NET — понятие сборки, которую можно рассматривать как логическую DLL. Сборки позволяют различным клиентам работать с различными версиями одного и того же компонента. Сборка содержит метаданные (манифест), используя которые система может еще до запуска клиента узнать — имеются ли все нужные клиенту компоненты в доступных сборках.
Предположим, что код клиента содержится в файле MуАрр. cs рабочего каталога, а код сервера в подкаталоге MyServer в файле MyServer.cs. Следующие команды обеспечивают компиляцию и сборку клиентского и серверного приложений:
>csc /t: library MyServer.cs
>csc /r: MyServer\MyServer.dll MyApp.cs
В первой строке вызывается компилятор с C# и код сервера MyServer.cs компилируется в сборку MyServer.dll. Ключ /t: library говорит именно о том, что нужна сборка типа DLL, т. е. ее можно загружать в домен клиентского приложения.
Во второй строке компилируется код клиента MуАрр. cs. По умолчанию получаем сборку МуАрр. ехе. Ключ /r: MyServer MyServer.dll дает статическую ссылку на сборку, содержащую компонент Account.
Отметим, что в данном случае сборка с сервером находится в одном каталоге с клиентом (точнее, в его подкаталоге, имя которого совпадает с именем сборки). Такой способ развертывания является самым простым. Он допускает перенос приложения в другой каталог, на другую машину простым копированием. Нет никакой регистрации.
Однако данной сборкой может пользоваться только данный клиент. Другим клиентам, находящимся вне рабочего каталога, данная библиотечная сборка недоступна.
Теперь запустим клиентское приложение
>csc МуАрр. ехе
Server AppDomain = МуАрр. ехе
Total = 8
Client AppDomain = МуАрр. ехе
Int32 Total
Void Add(Int32)
Int32 GetHashCode
Boolean Equals(System.Object)
System.String ToString
System.Type GetType
Мы видим, что и сервер и клиент выполняются в одном домене приложения. Его имя совпадает с именем клиентского приложения. Это связано с тем, что клиентская сборка загружается при запуске в домен приложения по умолчанию, который потом и получает свое имя, совпадающее с именем загруженной сборки. Серверная сборка загружается туда же.
Ниже выводятся сигнатуры всех методов, доступных через ссылку на любой интерфейс класса Account. Это и оба метода, реализованные в классе Account, и методы, унаследованные от System.Object.
Регистрация сборки в Global Assembly Cache
GAC — Global Assembly Cache, это то место, где можно развертывать сборки, которые должны быть доступны многим клиентам. Для развертывания сборки в GAC ее нужно подписать. Точнее, сборке присваивается версия, ее содержимое хешируется и хешированное значение шифруется личным ключом разработчика. В сборку (в ее манифест), включаются версия сборки, шифрованный хеш — электронная подпись, публичный ключ. В результате, благодаря наличию публичного ключа, можно проверить сохранность сборки, т. е. перед запуском клиентского приложения удостовериться, что именно с этой сборкой данное клиентское приложение было откомпилировано.
Ниже приведены все необходимые команды, обеспечивающие подписание сборки и ее регистрацию в GAC:
>csc /t: module MyServer.cs
>sn — k my.snk
>al /out: MyServer.dll MyServer.netmodule /keyfile: my.snk
>gacutil — i MyServer.dll
>sn — Tp MyServer.dll
Public key is
002400000480….
Public key token is 047772996d01a6d4
Для получения подписанной сборки (сборки со строгим именем) нужно откомпилировать код серверас параметром /t: module. В результате получим модуль MyServer.netmodule, содержащий (как и сборка) код на MSIL, но не содержащий (в отличие от сборки) манифеста.