рис. 22.2.
.Переход.между.доменами.в.окне.отладчика.Call.Stack
Когда реальный метод
SomeMethod
возвращает управление методу
SomeMethod
представителя, тот переправляет поток обратно в основной домен, в котором и про-
должается выполнение кода.
620
Глава.22 .Хостинг.CLR.и.домены.приложений
ПриМеЧание
Когда.поток.в.одном.домене.вызывает.метод.другого.домена.приложений,.поток.
переходит.от.домена.к.домену .Это.означает,.что.вызовы.метода.через.границу.между.
доменами.приложения.выполняются.синхронно .Однако.считается,.что.в.каждый.
момент.времени.поток.находится.только.в.одном.домене .Для.выполнения.кода.в.не-
скольких.доменах.приложений.одновременно.придется.создавать.дополнительные.
потоки.и.заставлять.их.выполнять.нужный.код.в.нужных.доменах
Далее мое приложение вызывает открытый статический метод
Unload
типа
AppDomain
, чтобы заставить CLR выгрузить указанный домен вместе со всеми
загруженными в него сборками. Одновременно инициируется уборка мусора для
освобождения всех объектов выгружаемого домена. На этом этапе переменная
mbrt
основного домена все еще ссылается на нужный объект-представитель; однако
сам объект-представитель больше не ссылается на нужный домен приложений
(поскольку тот уже выгружен). Когда основной домен пытается использовать
объект-представитель для вызова метода
SomeMethod
, вызывается реализация этого
метода, определенная в представителе. Реализация представителя выясняет, что
домен приложений, в котором находился реальный объект, уже выгружен, и метод
SomeMethod
генерирует исключение
AppDomainUnloadedException
, информируя
вызывающий код о невозможности выполнения операции.
Как видите, команда разработчиков CLR в Microsoft проделала огромную работу,
чтобы обеспечить изоляцию доменов приложений. И это дело исключительной важ-
ности, так как данная функциональность все активнее используется при решении
повседневных задач. Ясно, что доступ к объектам через границы доменов посред-
ством продвижения по ссылке связан с некоторой потерей производительности,
поэтому использование таких операций надо сводить к минимуму.
Я обещал подробнее рассказать об экземплярных полях. Они определяются
в типе, производном от
MarshalByRefObject
, однако не являются частью представи-
теля и отсутствуют в объекте-представителе. Когда вы пишете код, читающий и из-
меняющий значения полей экземпляров типа, производного от
MarshalByRefObject
,
JIT-компилятор генерирует код, использующий объект-представитель (чтобы
найти реальные домен и объект), вызывая соответственно метод
FieldGetter
или
FieldSetter
класса
System.Object
. Это закрытые и недокументированные методы;
в сущности, для считывания и записи значений в поле в них используется отражение.
Так что хотя вы и имеете доступ к полям типа, производного от
MarshalByRefObject
,
производительность от этого страдает особенно сильно, потому что для такого до-
ступа среде CLR приходится вызывать методы. Производительность значительно
снижается, даже если объект, к которому происходит обращение, находится в ло-
кальном домене приложений
1
.
1
Если бы среда CLR требовала закрытости всех полей (что рекомендуется для хорошей
инкапсуляции), методы FieldGetter и FieldSetter не должны были бы существовать. В итоге
к полям остался бы только непосредственный доступ из методов, что избавило бы нас от
потерь производительности.
Do'stlaringiz bilan baham: |