【C#進階系列】22 CLR寄宿和AppDomain

来源:http://www.cnblogs.com/vvjiang/archive/2016/04/19/5406590.html
-Advertisement-
Play Games

關於寄宿和AppDomain 微軟開發CLR時,將它實現成包含在一個DLL中的COM伺服器。 任何Windows應用程式都能寄宿(容納)CLR。(簡單來講,就是CLR在一個DLL中,通過引用這個DLL,可以實現包含CLR) CLR COM伺服器初始化會創建一個預設AppDomain,這個AppDom ...


關於寄宿和AppDomain

微軟開發CLR時,將它實現成包含在一個DLL中的COM伺服器。

任何Windows應用程式都能寄宿(容納)CLR。(簡單來講,就是CLR在一個DLL中,通過引用這個DLL,可以實現包含CLR)

CLR COM伺服器初始化會創建一個預設AppDomain,這個AppDomain只有在進程終結時才會被銷毀。

然而宿主程式還可以要求CLR創建額外的AppDomain。

因為創建進程開銷很大,並且需要大量記憶體來虛擬化進程的地址空間。

所以人們就像可不可以在一個進程上運行多個程式呢。

於是就在進程上寄宿CLR,並除了AppDomain的概念。AppDomain是為了提供隔離而設計的。

當然原因不止如此,寄宿為應用程式提供了自定義和可擴展性的能力,然而這會導致一些惡意dll去破壞應用程式的數據結構和代碼,還能利用安全上下文來訪問本來無權訪問的資源。

CLR的AppDomain可以解決這個問題,允許第三方的不受信任的代碼在現有進程中運行,而CLR保證數據結構、代碼和安全上下文不被濫用和破壞

AppDomain,看名字就知道:應用程式域。

以下為AppDomain的具體功能:

  • 一個AppDomain的代碼不能訪問另一個AppDomain的代碼創建的對象。這樣就將兩個AppDomain隔離開來,這種隔離使AppDomain很容易在進程中卸載,不會影響其它AppDomain正在運行的代碼。
  • AppDomain可以卸載。(前面提到過,預設的第一個AppDomain是不能卸載的)
  • AppDomian可以單獨保護。(每個AppDomain都會有自己的許可權集)
  • AppDomain可以單獨配置。(每個AppDomain都會有自己的配置設置,主要影響CLR在AppDomain中的載入方式。涉及搜索路徑、版本綁定重定向、捲影複製以及載入器優化)

一個進程上面運行一個CLR COM伺服器,然後該CLR管理多個AppDomain,每個AppDomain可以有自己獨立的程式。有的程式集是可以在AppDomain中共用的,比如MSCorLib.dll這種與.NET密不可分的類型,在CLR初始化時會被自動載入,有自己獨有的loader堆去維護類型對象,且作為"AppDomain"中立的方式為所有AppDomain共用。

跨越AppDomain邊界訪問對象

前面講到AppDomain就是為了隔離而設計的,且一個AppDomain的代碼不能訪問另一個AppDomain的代碼。

然而要去做到也不是沒有辦法,為了實現兩個AppDomain之間的通信。

按照AppDomain通信可以將類型分為三種:按引用封送類型,按值封送類型,完全不能封送的類型。

進程中可以有多個線程和多個AppDomain,然而它們不是一一對應的。

雖然一個線程一次只能執行一個AppDomain中的代碼,但是一個線程可以執行一個AppDomain的代碼後再去執行另一個AppDomain的代碼,並且還可以查看自己在哪個AppDomain中。

然而這裡由於感覺用不到關係,而且有點小複雜,所以就只領會了中心思想:

按引用封送:實際上就是AppDomain比如B傳給另一個AppDomain比如A一個引用對象b,當執行b的函數時,實際上是線程又切回了B,調用完後再切回A。

按值封送:這個實際上就是將一個AppDomain中的對象序列化然後放到另一個AppDomain進行反序列化中。

卸載AppDomain

調用靜態方法AppDomain.Unload即可。

卸載AppDomain會卸載其中的所有程式集,釋放loader堆。

主要步驟:

  1. CLR掛起進程中執行過托管代碼的所有線程
  2. 查看那些線程正在執行要卸載的AppDomain中的代碼,有就強迫對應的線程拋出一個ThreadAbortException(線程中止異常)並恢復執行線程,這將導致執行遇到的所有的finally塊以清理資源。如果沒有代碼捕捉到這個異常,那麼finally就不會執行,但是線程會終止,但進程可繼續運行。(其它所有未處理的異常我們在前面講過會終止進程,而這裡只會終止這個線程.
  3. 執行完第二步,所有的線程都會離開此AppDomain,CLR進入前面垃圾回收類似的標記階段,標記垃圾。
  4. CLR強制執行垃圾回收,這些對象的Finalize方法被調用來正確清理占用的資源。
  5. CLR恢復所有線程的執行。

任何時候都只會有一個線程來調用Unload方法,不會有多個線程同時調用。

宿主如何使用AppDomain

控制台UI應用程式,NT Service應用程式,Windows窗體應用程式和WPF應用程式都是自寄宿(即自己容納CLR)的應用程式。

它們都有托管exe文件,托管exe文件初始化進程後,會載入“墊片”(即MSCorEE.dll),墊片檢查應用程式集的CLR頭信息,決定載入哪個版本的CLR到進程中,CLR載入完後再次檢查CLR頭去茶砸後Main函數,然後調用該方法後程式才算真正啟動起來。

再舉一個例子,就拿ASP.NET來說,客戶端請求一個Web應用程式時,如果是第一次請求,那麼就ASP.NET要求CLR創建新的AppDomain,每個Web應用程式根據虛擬根目錄來標識,然後讓CLR將包含應用程式所公開類型的程式集載入到新的AppDomain中,創建實例,並調用其中方法。如果不是第一次請求就不會創建新的AppDomain。然而如果客戶端請求不同的Web應用程式,也會創建新的AppDomain。貌似就說的是IIS里的那些不同的網站。

 

小總結:

到這一步,還是打算講一下自己對這個東西的理解。

對於.NET的世界而言,都是在一個進程之上載入CLR(CLR COM伺服器),然後在這個CLR上再載入不同的AppDomain。

對於我們平常寫的那些簡單用.net創建的程式如控制台程式,實際上也是在一個托管exe上再載入CLR,而此時會載入了預設的一個AppDomain。此exe可以作為一個宿主去載入更多的AppDomain,然而這就需要自己手動去載入了。

而對於那些不是.NET的非托管應用程式,也是可以載入CLR,而此時也會載入了預設的一個AppDomain,實際上它也可以作為一個宿主去載入更多的AppDomain。

可能有偏差,還望指正!

PS:

本章內容只擇其精要寫了一下,具體的AppDomain的玩法需要的時候再進一步深究。(話說回來,總有一種一輩子玩不到這個東西的感覺)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在整型信號量機制中,信號量被定義為一個整形變數。除初始化外,僅能通過兩個標準的原子操作Wait(S)和Signal(S)來訪問。其通常分別被稱為P、V操作。 描述如下: P操作:S=S-1;如果S小於0,則進程進入等待狀態,否則繼續執行。 V操作:S=S+1;如果S>=0,則喚醒等待隊列中的一個等待 ...
  • 首先在開始正文之前先介紹最簡單的獲取進程/線程句柄方法。那就是可以在創建進程/線程時獲取句柄。 創建進程/線程是獲取句柄。 //進程創建函數 BOOL CreateProcess( PCTSTR pszApplicationName, PTSTR pszCommandLine, PSECURITY_... ...
  • 第一、檢查硬碟設備是否有數據盤 第二、數據硬碟分區 第三、ext3格式化分區 第四、掛載新分區 A - 新建目錄[任意創建] B - 掛載分區 第五、寫入fstab 設置開機自動掛載 第六、檢查是否掛載成功(df -h ) ...
  • bmp.c:8: warning: malformed '#pragma pack(push[, id], <n>)' - ignored bmp.c:33: warning: #pragma pack (pop) encountered without matching #pragma pack ...
  • 反射的定義:審查元數據並收集關於它的類型信息的能力。元數據(編譯以後的最基本數據單元)就是一大堆的表,當編譯程式集或者模塊時,編譯器會創建一個類定義表,一個欄位定義表,和一個方法定義表等。System.reflection命名空間包含的幾個類,允許你反射(解析)這些元數據表的代碼 System.Re ...
  • 在ASP.NET中,頁面間數據傳遞的方法有很多。下麵為大家總結一下,頁面間數據傳遞的方法。 Web頁面是無狀態的,伺服器對每一次請求都認為來自不同用戶,因此,變數的狀態在連續對同一頁面的多次請求之間或在頁面跳轉時不會被保留。在 用ASP.NET 設計開發一個Web系統時, 遇到一個重要的問題是如何保 ...
  • 前言 作為一名.NET程式員,很多時候都會被什麼拖控制項、跨平臺等字眼所鄙視過,但是在我的的內心還是沒有把自己看低過。因為說到底,平臺和語言只是我們吃飯的工具。很多時候公司的發展是取決於商業競爭的,微軟也不例外。在大環境下,我們終於看到了微軟給我們帶來的跨平臺的驚喜。儘管這隻是剛剛開始,但我相信在不久 ...
  • 本來是想試著做一個簡單OA項目玩玩的,真是不做不知道,一做嚇死人,原來以為很簡單的事情,但是做起來不是忘這就是忘那的,有的技術還得重新溫習。所以還是得記錄。免得哪天電腦掛了,就全沒有了。 開始是看了園子里何鎮汐的一系列文章,寫的太好了,只看了幾篇就有想寫代碼的衝動,很大一部分都是搬他的東西。但是我還 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...