Совместно используемые и частные сборки
Сборки бывают двух типов: совместные и частные. Частные сборки Частные сборки являются самым простым видом. Как правило, они поставляются в комплекте с программным обеспечением и будут использоваться исключительно этим программным обеспечением. Обычный способ поставки частных сборок - клиенту предоставляется приложение в виде исполняемого файла и набора библиотек, содержащих используемый приложением код. Система гарантирует, что частные сборки не будут применяться другим программным обеспечением, так как приложение может загружать только те частные сборки, которые расположены вместе с ним в одном каталоге или подкаталогах. Обычно предполагается, что коммерческий программный продукт устанавливается в свой собственный каталог, тем самым исключается всякий риск удаления, модификации сборок или загрузки частной сборки, предназначенной для использования другим приложением. Поскольку частные сборки могут применяться только тем приложением, для которого они предназначены, у пользователя есть возможность контролировать использование сборок тем или иным программным обеспечением. Следовательно, требуется предпринимать меньше усилий по обеспечению безопасности, так как не существует риска, например, того, что какое-то программное средство перепишет одну из сборок более новой версией (не считая, конечно, программ, написанных с целью умышленного нанесения ущерба). Также исключаются проблемы совпадающих, имен. Если классы в частной библиотеке имеют те же названия, что и классы в другой частной библиотеке, это уже неважно, поскольку приложение будет видеть только один набор частных сборок. Так как частная сборка полностью самоописываема, процесс инсталляции чрезвычайно прост. Необходимые файлы помещаются в указанный каталог на диске. Не требуется производить запись в реестре и другие подобные действия. Этот процесс называют установкойс нулевым усилием. Совместные сборки Совместные сборки - это общие библиотеки, которые могут использоваться любыми другими приложениями. Совместное использование требует учета следующих возможных опасностей: · Коллизии имен, затрагивающие совместную сборку от другой компании, реализующую типы, которые используют те же имена, что и ваша совместная сборка. Так как клиентский код теоретически может иметь доступ к обеим библиотекам, не исключено возникновение серьезных проблем. · Опасность перезаписи сборки другой версией той же сборки, причем новая версия может оказаться несовместимой с уже имеющимся клиентским кодом.
Решение этих проблем заключается в размещении совместных сборок в специальном поддереве каталогов файловой системы, известном как кэш сборок.В отличие от частных сборок, общую сборку нельзя просто скопировать в соответствующий каталог, ее необходимо установить в кэш. Этот процесс может быть осуществлен с использованием нескольких утилит .NET; при этом проводятся определенные проверки сборки, а также создание небольшой структуры каталогов внутри кэша сборок, которая используется для обеспечения целостности сборки. Во избежание риска коллизий имен совместные сборки именуются на основе криптографии с закрытым ключом (частные сборки имеют то же имя, что и основная программа). Это имя называется строгим именем(strong name), оно является гарантированно уникальным и должно применяться приложениями, которые желают обращаться к совместной сборке. Проблемы, связанные с риском перезаписи сборки, решаются указанием информации о версиях в манифесте сборки и обеспечением возможности сосуществования нескольких одноименных библиотек разных версий. Пространства имен Используя пространства имен, .NET избегает коллизий имен между классами. Пространства имен разработаны для исключения таких ситуаций, когда, например, определяется представляющий потребителя класс под названием Customer, и то же самое делает кто-то другой (весьма вероятный сценарий: процент бизнес-приложений, имеющих дело с потребителями, очень высок). Пространства имен - это нечто большее, чем простая группировка типов данных. Имена всех типов данных в определенном пространстве имен автоматически расширяются префиксом, образованным от названия пространства имен. Также можно создавать вложенные пространства имен. Например, большинство базовых классов .NET общего назначения расположено в пространстве имен System. Базовый класс Array находится в этом пространстве имен, поэтому его полное имя - System.Array. .NET требует, чтобы все типы были определены в некотором пространстве имен.
Например, можно было бы разместить класс Customer в пространстве имен YourCompanyName. Тогда класс имел бы полное имя YоurCompanyName. Customer. Если пространство имен не объявлено, то тип будет помещен в безымянное глобальное пространство имен. Microsoft рекомендует для указания класса в большинстве случаев использовать как минимум два вложенных пространства имен, одно из которых может быть, например, названием компании, а другое - названием технологии или программного пакета, к которому принадлежит данный класс (например, YourCompanyName.SalesServices.Customer). Выполнение этого условия защитит класс от возможной коллизии имен с классами, написанными в других организациях. Во многих языках пространства имен могут быть объявлены в исходном коде. Пример синтаксиса в С# : NamtSpaceYоurCompanyName.SalesServices { Class Customer // и т.д } Области приложений Области приложений являются важным нововведением .NET. Они разработаны для уменьшения накладных расходов по изоляции друг от друга запушенных приложений, которым требуется общаться друг с другом. Классический пример такого случая - приложение web-сервера, способное одновременно обрабатывать большое число запросов от браузеров. Оно будет иметь несколько одновременно запущенных экземпляров компонента, ответственного за обработку этих запросов. Раньше можно было бы позволить этим экземплярам использовать общий процесс, что способно привести к остановке всего web-сайта в случае зависания хотя бы одного процесса, или изолировать эти экземпляры в разных процессах, что вызывает соответствующее увеличение накладных расходов.
Вообще, любой процесс может обращаться к памяти только путем указания адреса в виртуальной памяти - процесс не имеет прямого доступа к физической памяти. Следовательно, один процесс ни в каком случае не может получить доступ к памяти другого процесса. Это дает гарантию того, что плохой код не сможет повредить ничего за пределами своего адресного пространства. (Отметим, что в Windows 9x это реализовано не так хорошо, как в NT/2000, и там существует теоретическая возможность нарушения работы Windows путем доступа к чужой памяти.) Процессы служат не только для отделения друг от друга различных экземпляров исполняемого кода. В системах Windows NT/2000 они также образуют блок, с которым связаны привилегии доступа. Каждый процесс имеет свои собственные привилегии, которые показывают Windows, какие операции может выполнять данный процесс. Процессы хорошо подходят для обеспечения безопасности (для исключения доступа к чужим участкам памяти и для разграничения по привилегиям), но их недостатком является производительность. Нередко большое число процессов должно работать сообща и иметь возможность связи друг с другом. Типичный пример, когда процесс вызывает СОМ-компонент, который является исполняемым файлом и, следовательно, должен быть запущен в отдельном процессе. То же самое происходит в СОМ, где применяются замещения. Так как процесс не может использовать память совместно еще с кем-то, то для передачи данных между процессами должны применяться сложные функции переноса данных (marshalling). Это серьезно ухудшает производительность. Если необходимо, чтобы компоненты работали совместно и при этом не было потерь производительности, единственный способ - использование DLL и работа всего кода в едином адресном пространстве с риском того, что плохое поведение единственного компонента приведет к краху всей системы.
Если различные исполняемые файлы запущены в одном адресном пространстве, они могут свободно разделять данные, так как теоретически они способны напрямую видеть данные друг друга. Однако среда исполнения .NET не допускает этого на практике, проверяя код каждого запущенного приложения и убеждаясь в том, что код не может обращаться к чужим областям данных. На первый взгляд это кажется невозможным: как узнать, что собирается делать программа, не запуская ее? На самом деле это возможно благодаря строгому контролю типов в промежуточном языке. В большинстве случаев, если только код не использует небезопасные средства, например указатели, применяемые им типы данных будут гарантировать, что доступ к памяти осуществляется корректно. Скажем, массивы в .NET выполняют проверку границ для того, чтобы исключить выход за свои границы. Если приложению все же требуется общаться или обмениваться данными с приложениями, работающими в других областях приложений, то тогда должны использоваться удаленные службы .NET, представляющие собой различные базовые классы в пространстве имен System.Remoting. Код, в отношении которого в ходе проверки было установлено, что он не способен получить доступ к данным вне области приложения (кроме как посредством механизма удаленного сообщения), считается безопасным по типу (или безопасным по типу памяти). Такой код может безопасно исполняться вместе с другим безопасным по типу кодом в различных областях приложений внутри одного процесса.
J IT- компиляторы(Just-In-Time) Компилятор JIT является ключевым средством платформы .NET и жизненно важной составляющей в реализации попытки Microsoft сделать так, чтобы управляемый код работал с большей производительностью, чем неуправляемый. Проблема производительности возникает из-за того, что код компилируется в промежуточный язык, и это может стать неожиданностью для некоторых разработчиков. В конце концов, одним из недостатков Java является то, что процесс трансляции с байт-кода Java в исполняемый код в процессе выполнения программы означает потерю производительности. Однако существует все же большая разница, заключающаяся в том, что байт-код Java интерпретируется, a IL компилируется. Более того, JIT-компилятор компилирует не всю программу сразу (что может привести к излишне долгому запуску программы), а лишь кусок кода и именно тогда, когда он вызывается (отсюда название JIT-компилятора: Just-In-Time - вовремя). После того как код единожды откомпилирован, получившийся в результате машинный код сохраняется в памяти до тех нор, пока не будет осуществлен выход из программы, поэтому при следующем запуске того же самого кода его уже не потребуется компилировать. Microsoft считает, что это более эффективный процесс, чем компиляция всей сборки сразу, так как велика вероятность того, что большая часть кода сборки не будет выполняться во время одного конкретного запуска программы. При использовании JIT- компилятора такой код вообще не придется компилировать. Этим объясняется, почему исполнение управляемого кода на ILбудет почти таким же быстрым, как и исполнение родного машинного кода, но не объясняется, почему Microsoft ожидает подучить еще и улучшение по производительности. Дело в следующем: так как окончательная стадия компиляции происходит уже в процессе исполнения, JIT-компилятор точно знает, на каком процессоре будет работать программа. Это означает, что код может быть оптимизирован под использование тех особенностей, которые предлагаются каждым конкретным процессором. Традиционные компиляторы оптимизируют код, но они могут выполнять только оптимизацию, не зависящую от конкретного процессора. Это происходит из-за того, что современные компиляторы осуществляют компиляцию сразу в машинный код перед тем, как программа будет отправлена потребителю. Следовательно, компилятор не знает, на каком процессоре будет исполняться код. Ему могут быть известны лишь общие сведения, что это будет процессор семейства х86 или процессор Alpha. Visual Studio 6, например, оптимизирует код для процессора Pentium, поэтому такой код не сможет воспользоваться преимуществами процессора Pentium III. Напротив, JIT-компилятор может выполнить ту же оптимизацию, что и Visual Studio 6, но вдобавок оптимизировать код для того процессора, на котором он будет исполняться.
Инструменты .NET Помимо служб исполнения программы, .NET предоставляет ряд инструментов, которые призваны помочь в разработке приложений .NET: Visual Studio.NET - интегрированная среда разработки, с помощью которой можно писать, компилировать и отлаживать код на всех языках .NET, включая С#, VB.NET, управляемый C++, страницы ASP.NET и неуправляемый код C++. (ILDASM описывается в главе 8.) ·
· Компиляторы командной строки для С#, VB.NET и C++. · ILDASM - утилитас оконным интерфейсом, которую можно использовать для просмотра содержимого сборки, включая манифест и метаданные. ■
Сборщик мусора Сборщик мусора - это ответ .NET на проблемы управления памятью, в частности, на вопрос, связанный с перераспределением памяти, требующейся приложениям. До сих пор в Windows использовались две методики перераспределения памяти, динамически запрашиваемой процессами у системы: методика перераспределения памяти самим приложением и применение в объектах счетчиков ссылок.
В дополнение Java использует сборщик мусора, аналогичный работающему в .NET. Методика применения программного кода для перераспределения памяти используется низкоуровневыми высокопроизводительными языками, например C++. Эта методика эффективна и имеет то преимущество, что ресурсы не используются сверх положенного срока. Однако большим недостатком является значительное число ошибок. Код, который запрашивает память, должен в конце информировать систему о том, что память ему больше не требуется. В C++ для этого предусмотрено ключевое слово delete, кроме того, существуют различные функции API, предназначенные для той же цели. Программисты должны быть очень осторожны и внимательно следить за тем, чтобы освобождалась вся используемая память. Об этом нередко забывают, что приводит к утечкам памяти. Современные среды разработчика предоставляют инструменты для обнаружения утечек памяти, но эти ошибки все же очень сложно выявить, так как проявляются они лишь тогда, когда происходит утечка большого количества памяти и Windows в определенный момент просто отказывается выделить память процессу из-за ее отсутствия. К этому моменту работа всего компьютера может сильно замедлиться из-за потребления большого объема памяти. Использование счетчиков ссылок применяется СОМ-объектами. Идея заключается в том, что каждый СОМ-объект поддерживает информацию о том, как много клиентов в данный момент используют ссылки на него. Когда число ссылок становится равным нулю, компонент уничтожает себя и освобождает память и ресурсы. Проблема здесь заключается в том, что СОМ-объект рассчитывает на корректное поведение клиентов, которые должны сообщать ему об окончании своей работы с объектом (что осуществляется путем вызова метода IUnknown. Release ()). Стоит только одному из клиентов не сделать этого, и объект останется в памяти. В некоторых случаях это является потенциально еще более серьезной проблемой, чем простая утечка памяти в C++, так как СОМ-объект может существовать в своем собственном процессе, а это означает, что он никогда не будет удален системой (в случае утечек памяти система, по крайней мере, может освободить всю память по завершении процесса). Какое же решение применяется в .NET? Среда исполнения .NET полагается на так называемый сборщик мусора, который представляет собой программу, чьей целью является освобождение памяти. Смысл заключается в том, что вся динамически запрашиваемая память распределяется в куче (что справедливо для всех языков). По мере того как .NET выясняет, что для данного процесса куча полностью заполняется и, следовательно, требует очистки, она вызывает сборщик мусора. Сборщик мусора просматривает переменные кода, находящиеся в данный момент в области видимости, исследуя ссылки на объекты, хранящиеся в куче, для определения того, какие из них доступны в коде, или иными словами, какие объекты содержат ссылки на себя. Все объекты, на которые нет ссылок, считаются более недоступными из кода и должны быть уничтожены. Посмотрим, как это работает на практике, воспользовавшись фрагментом кода на С#: { TextBox UserInputArea; // Объявили переменную UserInputArea = new TextBox(); // В куче создается экземпляр объекта TextBox TextBox TextBoxCopy = UserInputArea; // Объявление с инициализацией
// Допустим, что сборщик мусора вызван здесь // Обработка данных } // Теперь UserInputArea и TextBoxCopy находятся вне зоны видимости кода //Допустим, что здесь снова был вызван сборщик мусора
Код начинается с объявления переменной типа TextBox. Эта переменная имеет имя UserInputAreа. TextBox является типом по ссылке. Это означает, что UserlnputArea содержит адрес, и нам необходимо отдельно создать экземпляры объектов TextBox в куче, что делается в следующей строке. Затем мы объявляем еще одну переменную, TextBoxCopy, и присваиваем ей значение UserlnputArea, т.е. она тоже ссылается на TextBox. Теперь допустим, что это происходит в тот момент, когда вызывается сборщик мусора. Просматривая ссылки по коду, он обнаружит, что обе переменные ссылаются на TextBox. Очевидно, что объектTextВохдо сих пор используется и должен оставаться в куче. Сборщик мусора не только удаляет объекты - он может упорядочивать кучу для повышения производительности. Поэтому существует вероятность того, что он изменит местоположение данных для объекта TextBox. Если это будет сделало, то он обновит адреса, содержащиеся в UserlnputArea и txtBoxCopy. Затем переменные UserlnputArea и txtBOxCopy выходят из области видимости. Допустим, что больше никакие переменные не ссылаются на TextBox и что в этот момент снова вызывается сборщик мусора. Теперь он обнаружит, что существует область в куче, используемая для хранения TextBox, и что на эту область не ссылается ни одна из видимых переменных. Исходя из этого, сборщик мусора решит, что TextBox больше не требуется, и удалит его. Отметим, что данный механизм совершенно безопасен: если наTextBox нет ссылок, то не существует законного пути, посредством которого код сможет снова получить доступ к TextBox. Промежуточный язык не обеспечивает каких-либо безопасных способов получения ссылки на объект в куче, кроме как его создание или копирование уже существующей ссылки. Если нет ссылки, которую можно скопировать, он не способен законно получить ссылку на существующий объект. Здесь мы говорим "законно", так как теоретически можно написать небезопасный код на С# или C++, который будет использовать указатели, арифметику указателей и преобразование типов для повторного получения ссылки на TextBox. Однако здесь не видно никаких причин, по которым кто-то захотел бы сделать это, кроме как для того, чтобы продемонстрировать саму возможность подобных действий,- определенно, это не в духе методологии .NET. Ссылку можно получить более простым способом - написав код, который никогда не потеряет ее! Сборка мусора работает потому, что промежуточный язык был спроектирован для облесения этого процесса. Требуется, первое, чтобы ссылки на существующие объекты нельзя было получить иначе, кроме как копированием имеющихся ссылок на объекты, и второе, чтобы промежуточный язык был безопасным по типам. В этом контексте под безопасностью по типам понимается то, что если существует ссылка на объект, то в этой ссылке присутствует достаточно информации для точного определения типа объекта. Механизм сборки мусора невозможно было бы применять с таким языком, как неуправляемый C++, поскольку C++ допускает свободное преобразование типов указателей. Это означает, что ни одна из программ, просматривающих код, не сможет определить по значениям указателей, какие участки кучи используются на данный момент. Как уже отмечалось ранее, IL допускает применение указателей в небезопасном коде, а также позволяет преобразовывать тип указателя. Однако в IL существуют жесткие ограничения на использование указателей, которые были разработаны таким образом, чтобы их применение в коде не конфликтовало с требованиями сборщика мусора. Б частности, указатели не могут указывать на ссылочные объекты. Важной особенностью сборки мусора является то, что это недетерминированный процесс. Нельзя сказать, когда будет вызван сборщик мусора: он вызывается тогда, когда среда исполнения .NET решает, что его необходимо вызвать. Очевидно, что чем больше требований программа предъявляет по части памяти, тем чаще будет вызываться сборщик мусора. Сборщик мусора можно вызвать из программы вручную с помощью базового класса .NET System.GC. Это можно сделать, например, в точке, где код заканчивает работу с большим числом переменных. В большинстве ситуаций, однако, придется довериться среде исполнения .NET, которая сама будет вызывать сборщик мусора при необходимости.
Популярное: Как построить свою речь (словесное оформление):
При подготовке публичного выступления перед оратором возникает вопрос, как лучше словесно оформить свою... Как распознать напряжение: Говоря о мышечном напряжении, мы в первую очередь имеем в виду мускулы, прикрепленные к костям ... Организация как механизм и форма жизни коллектива: Организация не сможет достичь поставленных целей без соответствующей внутренней... Почему люди поддаются рекламе?: Только не надо искать ответы в качестве или количестве рекламы... ©2015-2024 megaobuchalka.ru Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. (600)
|
Почему 1285321 студент выбрали МегаОбучалку... Система поиска информации Мобильная версия сайта Удобная навигация Нет шокирующей рекламы |