Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 117
Текст из файла (страница 117)
° Включающий тип должен реализовать 101зрозапуе, потому что содержит экземпляр Б11езсгезп, реализующий 101зрозаь1е. В конце концов, если тип содержит приватный экземпляр Б11езггеав, то без реализации 1РБзроззЬ1е клиенты типа не смогут контролировать то, когда Б11еБСгеаи закроет свой неуправляЕ- мый дескриптор файла. ° Включающий тип не должен реализовывать финализатор, поскольку включаемый экземпляр Б11еБггеаи закроет лежащий в основе дескриптор файла операционной системы. Включающий тип должен реализовывать финализатор только в том случае.
если он непосредственно содержит неуправляемый ресурс. Следует обратить внимание на то, что Р1зрозе никогда не вызывается автоматически, и на то, как финализатор может помочь в решении потенциальных проблем эффективности у клиентов. Предположим, что создается объект, который выделяет нетривиальную порцию неуправляемых системных ресурсов. Затем клиент этого объекта создает веб-сайт, который посещается много раз за минуту, причем при каждом посещении создается новый экземпляр объекта. Производительность клиентской системы существенно снизится, если клиент забудет своевременно освободить зти объекты перед тем, как ссылки на них исчезнут. Конечно, если реализовать финэлизатор так, как было показано ранее, то объект в конечном итоге будет освобожден.
Однако это произойдет, только когда ОС сочтет это необходимым, поэтому вероятно истощение ресурсов системы. Более того, если забыть вызвать Рьзроее. то это, скорее всего, приведет к увеличе- В поисках канонических форм С№ 439 нию объема финвлизации, что еще больше нагрузит ОС. Клиентский код может принудительно инициировать работу ОС через вызов метода БС.
Со11ест. Однако поступать твк настоятельно не рекомендуется, поскольку это означает вмешательство в алгоритм работы ОС. В 99,990 случаев сборщик мусора лучше знает, как управлять памятью. Было бы неплохо иметь возможность информировать клиентов объекта, когда они забывают вызвать Оуярояе в своих отладочных сборках. И действительно, можно протоколировать ошибку всякий раз, когда запускается финзлизатор объекта, извещая о том, что объект не был освобожден правильно. Можно даже указать клиентам точное место создания объекта, выводя трассировку стека в точке создания. Таким образом, они будут знать, какая строка кода создает объект-нарушитель.
Давайте модифицируем пример Хуп32Неар в соответствие с этим подходом. иятпд Буятев; ия1пд Яуятев.кипт1ве.1птеторЯети1сез! ия1пд Яуятев.01адпояттся! риЬ1тс яеа1еб с1азя Хтп32Неар: 10гярояаЫе ( (0111вротт (Ойегпе132. 611" ) ) ятатус ехтетп гптртг Неарсгеате(шпт 110рт1опя, 01птртт с(и1п1т1а151яе, 01птРГт Йннахтвив51те)! (0111врогт(")сетпе132.б11")) ятатгс ехгегп ьоо1 неарсеягтоу(1пгртт ьнеар)! риЬ1гс Х1п32Неар() ( стеатгопЯГасКТтасе = пен БтасКТгасе(1, итие); ГпеНеар = НеарСгеате( О, (01птртг) 4095, 01птртт.аего ) // Реализация 101ярояаЫе рт1иате ио1б Отярояе( Ьоо1 бтярояьп9 ) ( 11( )61ярояеб ) ( 11( с(тяроя!.п9 ) ( // Здесь допускается использовать любые внутренние объекты.
// Этот класс, однако, их не имеет. ) е1яе ( // Ны финалиэировали этот объект, а он не был освобожден. // уведомим пользователя, если только домен приложения // не завершит работу. Аррсова1п ситгептбова1п = Аррооватп.Сиггептбовагп! 11( !ситгептповатп.1зг1па11гтпдготцп1оаб() аа !Епитгопхсепт.НаяЯЬитбонпЯтаттеб ) ( Сопзо1е.нгттеьапе( "Сбой в освобождении объекта!!!" )! Сопяо1е.нтгтеь1пе( "Объект размещен в:" гот( 1пт т = О) г < стеаттопБтасКТтасе.ггавеСоипт; ++1 ( Бтасхгтаве Гтаве = стеаттапЯтасхтгасе.бетггаве(1)! Сопяо1е.нг!.те1,!.пе( " (0]", Ггаве.таБтт1пд() )! ) ) // Если используются объекты, о которых известно, // что они еще существуют, такие как объекты, 440 Глава (3 гг реалиэуюшие шаблон 31пг31егоп, важно убедиться, !г' что они являются безопасными з отношении потоков.
неароеэггоу( гпеНеар )г ГпеНеар = 1пГРГг.2его( бьзрсзеб = Ггпег ) ) рпЬ11с чоюа Еьзрозе() ( Р1эрозе( Ггпе )( СС.БпрргеззГзпа11зе( Гвтз ); ) -Нюп32Неар() ( Разрезе( Га1зе )г ) ргтчаге 1пгрсг Гленеар( ргтчасе Ьоо1 бззроэеб = Га1зег ргтчаге Бсасктгэсе сгеасзопзсасхтгасе( рпЬ11с зеа1еб с1азз ЕпсгуРо1пг зсас1с чоган Ма1п() ( Нгп32Неар Ьеар = пен Нтп32Неар(); Ьеар = пп11; БС.Со11есс()Г Сб.иаггрсгРепбапОГ1па11яегз(); ) ) В методе Ма1п распределяется новый объект н1п32неар, после чего немедленно вызывается его финализация. Поскольку объент не был освобожден, это вызывает код построения дампа стека внутри метода р1зрозе. Из-за того, что для случая выгрузки домена приложения, скорее всего, финализация объектов не предусмотрена, код построения дампа стека помещен в условный блок, зависящий от результата Аррроша1п.1зГ1па1121порогбп1оаб аа епчзгопшепг.назБьпьбонпБсаггеб. Если бы в Ма1п метод р1 ерове вызывался перед установкой ссылки в пз11, то трассировна стека не была бы отправлена на консоль.
Клиенты библиотеки могут быть благодарны за указание на неосвобожденные объекты. И зто правильно. На заметку! При компиляции предыдущего примера можно получить более осмысленный и читабельный вывод, если указать ключ компилятора /беЬпг3+, потому что в результате во время выполнения будет доступно больше символической информации и сведений о номерах строк. Включение генерации отчета может быть предусмотрено только для отладочных и тестовых сборок. Эта дискуссия должна была наглядно продемонстрировать опасности реализации финализаторов.
Они представляют собой потенциальную причину огромного расхода ресурсов, поскольку заставляют объекты существовать дольше, и при этом скрываются за безобидным синтаксисом деструкторов. Единственной компенсацией этого со стороны финализаторов является способность указать, где объекты не были освобождены правильно, но эту технику рекомендуется применять только в отладочных целях. Решив реализовать финализатор объекта, не забывайте о его влиянии на эффективность системы. По возможности написания финализаторов лучше избегать.
Е поисках канонических форм С№ 441 Разработчики, знакомые с финализаторамн, также осведомлены о цене, которую приходится платить в потоке финализации, проходящем по Г-достижимой очереди и вызывающем финализаторы объектов. Тем не менее, легко не заметить множество других скрытых затрат. Например, создание финализируемого объекта требует несколько больше времени, поскольку среда СЬК должна зафиксировать объект, как подлежащий финализации. Конечно, для одиночного экземпляра объекта эта цена весьма незначительна, но если будут создаваться десятки тысяч маленьких финализируемых объектов, цена очень быстро возрастет. Кроме того, некоторые версии СЬН создают только один поток финалиэации, так что при запуске кода на многопроцессорной системе несколько процессоров могут распределять финализируемые объекты быстрее, чем поток финализации будет нх очищать, и тогда возникнет проблема с ресурсами.
Что еще хуже: представьте, что будет, если один из финалнэаторов заблокирует поток на длительный период времени либо навсегда. Кроме того, несмотря на возможность представления зависимостей между финализируемыми объектами с помощью хитроумных приемов, помните, что команда разработчиков СЬН активно рассматривает вопрос перемещения финализации в пул потоков процесса вместо отдельного потока финализации.
Это означает, что все применяемые приемы финализации должны быть безопасными в отношении потоков. Помните об этом и по возможности избегайте реализации финализаторов. Что означает эквивалентность для данного обьекта? ОЬч есг. ЕЧоа1з — виртуальный метод, который вызывается для определения в наиболее общем виде эквивалентности двух объектов. На первый взгляд переопределение метода ОЬч ее с . ЕЧоа1 з может показаться тривиальным. Однако помните, что это одна из тех кажущихся простыми вещей.
которые легко превращаются в семантический клубок. Ключом к пониманию ОЬ№есс. Еооа1з являются два семантических значения эквивалентности в СЬК. Эквивалентность по умолчанию для ссылочных типов, т.е. объектов, означает эквивалентность идентичности. Другими словами, две отдельные ссылки считаются эквивалентными.
если оии обе ссылаются на один и тот же экземпляр объекта в куче. Таким образом. для эквивалентности идентичности, даже если две ссылки указывают на объекты с совершенно одинаковым внутренним состоянием. то ОЬч ес с . Ейоа1з вернет для них значение га1зе. Другой формой эквивалентности в СЬН является эквивалентность значений. Этот тип эквивалентности в С№ по умолчанию принят для типов значений,или структур.










