<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      關于CLR內存管理一些深層次的討論[上篇]

      半年之前,PM讓我在部門內部進行一次關于“內存泄露”的專題分享,我為此準備了一份PPT。今天無意中將其翻出來,覺得里面提到的關于CLR下關于內存管理部分的內存還有點意思。為此,今天按照PPT的內容寫了一篇文章。本篇文章不會在討論那些我們熟悉的話題,比如“值類型引用類型具有怎樣的區(qū)別?”、“垃圾回收分為幾個步驟?”、“Finalizer和Dispose有何不同”、等等,而是討論一些不同的內容。整篇文章分上下兩篇,上篇主要談論的是“程序集(Assembly)和應用程序域(AppDomain)”。也許有的地方說的不是很正確,希望讀者不吝賜教。

      一、程序集與應用程序域

      何謂程序集(Assembly)?它是一個托管應用的基本的部署單元。一個程序集是自描述的(通過元數據)、能夠實施版本策略和部署策略。我傾向于這樣的方式來定義程序集:“Assembly is a reusable, versionable, and self-describing building block of a CLR application.”從結構組成來看,一個程序集主要由三個部署組成:IL指令元數據資源。程序集的結構組成如下圖所示。

      image那么什么又是應用程序域呢?從功能上講,通過應用程序域實現(xiàn)的隔離機制為托管代碼的執(zhí)行提供了一個安全的邊界。從與程序集的關系來講,我們可以將應用程序域看成是加載程序集的容器。只有相關的程序集被CLR加載到相應的應用程序域中,才談得上代碼的執(zhí)行。

      基于應用程序域的隔離,歸根結底是內存的隔離。一個基本的反映就是:在一個應用程序域中創(chuàng)建的對象,不能直接在另一個應用程序域中使用。這中間需要有一個基本的跨應用程序域傳遞的機制,我們將這種機制稱之為“封送(Marshaling)”。具體來講,又具有兩種不同的封送方式:按值封送(MBV:Marshaling By Value )和按引用封送(MBR:Marshaling By Reference)。MBV主要采用序列化的方式,而MBR最典型的就是.ENT Remoting。

      二、系統(tǒng)程序域、共享程序域和默認程序域

      image 當托管應用被啟動后,在執(zhí)行第一句代碼之前,CLR會先后為我們創(chuàng)建三個應用程序域:系統(tǒng)程序域(System Domain)、共享程序域(Shared Domain)和默認程序域(Default Domain),它們分別具有不同的作用。

      • 系統(tǒng)程序域:系統(tǒng)程序域是第一個被創(chuàng)建的應用程序域,同時也是其他兩個應用程序域的創(chuàng)建者。在該程序域初始化過程中,由它將msCorLib.dll這個程序集(這是一個很重要的程序集,.NET類型系統(tǒng)最基本的類型定義其中)加載到共享程序域中。此外,駐留的字符串也被保存在此系統(tǒng)程序域中。系統(tǒng)程序域的一個主要的任務是追蹤其他所有應用程序域的狀態(tài),并負責加載和卸載它們;
      • 共享程序域:共享程序域主要用于保存以“中立域(Domain-neutral Domain )”加載的程序集容器。所謂“中立域 ”方式加載的程序集,就是說程序集并不被加載到當前的程序域中并被該程序域專用,而是加載到一個公共的程序域中被所有程序域共享。
      • 默認程序域:我們的托管程序最終就運行在該程序域中,默認程序域可以通過System.AppDomain表示。

      三、字符串的駐留

      上面的文字描述實際上透露一些重要的信息,其中一個就是字符串的駐留(String Interning)。關于字符串的駐留,我想大家都不陌生,所以在這里我就不作重復的介紹了。在這里,我只想討論一個問題:字符串的駐留是基于整個進程的,不是僅僅基于某個應用程序域

      從上面的描述我們知道,字符串對象和一般的引用類型對象具有很大的不同:字符串對象直接被保存到系統(tǒng)程序域中,而一般的引用類型對象我們都是最終保存在GC堆中。從某種意義上講,在字符串駐留機制下,字符串也是以“中立域”的方式被加載的,被駐留的字符串能夠被同一個進程下所有應用程序域所共享。

      那么,我們是否可以通過一些比較直觀的方式來驗證這一點。但是,我們不能直接編寫程序來比較兩個應用程序域中字符串是否是相同的引用,但是我們有一些間接的機制。我個人喜歡采用的方式是:加鎖。我們在運行于不同的應用程序域的代碼中對兩個字符串變量進行加鎖,如果程序運行的結果和對相同的對象加鎖一樣,那么就可以證明被枷鎖的兩個對象實際上是同一個對象。

      為了便于演示,我寫一個如下一個AppDomainContext,表示某個AppDomain對應的執(zhí)行上下文。AppDomainContext具有一個只讀的類型為AppDomain的屬性,該屬性通過構造函數執(zhí)行,最終在靜態(tài)方法NewContext被創(chuàng)建。我們調用Invoke方法讓指定的方法對應的應用程序域中執(zhí)行。

         1: public class AppDomainContext
         2: {
         3:     public AppDomain AppDomain { get; private set; }
         4:     private AppDomainContext(AppDomain appDomain)
         5:     {
         6:         this.AppDomain = appDomain;
         7:     }
         8:     public static AppDomainContext NewContext(string friendlyName)
         9:     {
        10:         return new AppDomainContext(AppDomain.CreateDomain(friendlyName));
        11:     }
        12:  
        13:     public void Invoke<T>(Action<T> action) where T : MarshalByRefObject
        14:     {
        15:         T instance = (T)this.AppDomain.CreateInstanceAndUnwrap(typeof(T).Assembly.FullName, typeof(T).FullName);
        16:         action.Invoke(instance);
        17:     }
        18: }

      我們接著在定義一個輔助類ObjectLock方便進行加鎖,以及確認對象是否被所住。ObjectLock比如繼承自MarshalByRefObject,因為我們需要該對象以MBR的方式進行傳遞。在Lock方法中對指定的對象進行加鎖,并指定加鎖的時間。在CheckLock中通過時間間隔判斷指定的對象是否已經被鎖住,相應的結果會在控制臺中被輸出。為了讓大家能夠確定相應的操作是在哪個應用程序域中執(zhí)行的,在枷鎖和檢查鎖定的時候將應用程序域的名稱(AppDomain.FriendlyName屬性)打印出來。

         1: public class ObjectLock : MarshalByRefObject
         2: {
         3:     public void Lock(object objectToLock, int millisecondsTimeout)
         4:     {
         5:         lock (objectToLock)
         6:         {
         7:             Console.WriteLine("[{0}] Successfully lock the object.", AppDomain.CurrentDomain.FriendlyName);
         8:             Thread.Sleep(millisecondsTimeout);
         9:         }
        10:     }
        11:     public void CheckLock(object objectToLock)
        12:     {
        13:         if (Monitor.TryEnter(objectToLock, 10))
        14:         {
        15:             Console.WriteLine("[{0}] The object is not  locked.", AppDomain.CurrentDomain.FriendlyName);
        16:         }
        17:         else
        18:         {
        19:             Console.WriteLine("[{0}] The object is locked .", AppDomain.CurrentDomain.FriendlyName);
        20:         }
        21:     }
        22: }

      然后我再一個控制臺應用中的Main方法中,編寫了如下簡單的代碼。通過AppDomainContext在一個的應用程序域(Foo)中鎖定一個值為“Hello World!”的字符串,并在另一個應用程序域(Bar)中確認同值得字符串是否已經被鎖定。結果表示在應用程序域Bar中指定的字符串已經被鎖定,從而證明了應用程序域Foo和Bar中兩個值為“Hello World!”的字符串對象實際上是同一個。

         1: static void Main(string[] args)
         2: {
         3:     Action<ObjectLock> lockObj = objLock => objLock.Lock("Hello World!", 2000);
         4:     Action<ObjectLock> checkLock = objLock => objLock.CheckLock("Hello World!");
         5:  
         6:     Thread lockObjThread = new Thread(() => AppDomainContext.NewContext("Foo").Invoke<ObjectLock>(lockObj));
         7:     Thread checkLockThread = new Thread(() => AppDomainContext.NewContext("Bar").Invoke<ObjectLock>(checkLock));
         8:  
         9:     lockObjThread.Start();
        10:     Thread.Sleep(500);
        11:     checkLockThread.Start();           
        12: }

      輸出結果:

         1: 1: [Foo] Successfully lock the object.
         2: 2: [Bar] The object is locked.

      上面的介紹同時說明一個問題:千萬不要對一個字符串對象加鎖

      四、程序集加載的方式

      imageimage 雖然我們說CLR在啟動托管應用的時候,以中立域的方式加載msCorLib.dll這個程序集,但是這不是程序集默認采用的加載方式。在默認的情況下,程序集被加載到當前的程序域中,供該程序集獨占使用。我個人將這兩種不同的程序集加載方式稱為:獨占加載(Exclusive Loading )共享加載(Shared Loading)。如右圖所示:如果某個類型被定義在程序集中Foo.Dll,當AppDomain1和AppDomain2需要使用該類型的時候,它們會分別以獨占的方式加載程序集Foo.Dll。但是,如果它們使用一些基元類型,比如System.Object、System.Int32、System.DateTime等,則不會加載定義它們的msCorLib.dll程序集,而是直接使用已經被以中立域方式加載到共享程序域中的msCorLib.dll。

      我們同樣可以借助上面定義的AppDomainContext來證明這一點。在這之前我需要說明一點:程序集的加載包括對定義在程序集中類型系統(tǒng)的加載,我們可以通過類型對象的加鎖情況來推斷程序集的加載方式。為此我在上面創(chuàng)建的解決方案中添加了一個類庫項目Lib,ConsoleApp引用Lib項目,并在Lib中定義了一個空的Foo類型。

         1: namespace Artech.MemAllocation
         2: {
         3:     public class Foo
         4:     {}
         5: }

      然后我們修改之前的程序,將對字符串加鎖替換在對Foo類型(typeof(Foo))加鎖。從輸出結果我們可以看出,在Bar程序域中使用的Foo類型并沒有被鎖住,從而證明兩個程序域(Foo和Bar)使用的同一個類型并不是Type對象,因為對應的程序集是以獨占的方式加載的。

         1: static void Main(string[] args)
         2: {
         3:     Action<ObjectLock> lockObj = objLock => objLock.Lock(typeof(Foo), 2000);
         4:     Action<ObjectLock> checkLock = objLock => objLock.CheckLock(typeof(Foo));
         5:  
         6:     Thread lockObjThread = new Thread(() => AppDomainContext.NewContext("Foo").Invoke<ObjectLock>(lockObj));
         7:     Thread checkLockThread = new Thread(() => AppDomainContext.NewContext("Bar").Invoke<ObjectLock>(checkLock));
         8:  
         9:     lockObjThread.Start();
        10:     Thread.Sleep(500);
        11:     checkLockThread.Start();
        12: }

      輸出結果:

         1: [Foo] Successfully lock the object.  
         2: [Bar] The object is not locked.

      但是,如果我們將加鎖和鎖定檢驗的typeof(Foo)替換成typeof(int),結果就完全不一樣了。不同的結果說明了msCorLib.dll采用了不同于上面的程序集加載方式,以中立域方法的加載方式決定在任何應用程序域中使用的類型都是同一個Type對象。

         1: static void Main(string[] args)
         2: {
         3:     Action<ObjectLock> lockObj = objLock => objLock.Lock(typeof(int), 2000);
         4:     Action<ObjectLock> checkLock = objLock => objLock.CheckLock(typeof(int));
         5:  
         6:     Thread lockObjThread = new Thread(() => AppDomainContext.NewContext("Foo").Invoke<ObjectLock>(lockObj));
         7:     Thread checkLockThread = new Thread(() => AppDomainContext.NewContext("Bar").Invoke<ObjectLock>(checkLock));
         8:  
         9:     lockObjThread.Start();
        10:     Thread.Sleep(500);
        11:     checkLockThread.Start();
        12: }

      輸出結果:

         1: [Foo] Successfully lock the object.
         2: [Bar] The object is locked.

      五、我們自己的程序集也可以采用中立域的方式加載嗎?

      我想到這里有人會問一個問題:“我們自定義的程序集可以像msCorLib.dll一樣以中立域的方式共享加載嗎?”。對于控制臺應用,你只需要在Main方法上應用LoaderOptimizationAttribute特性,并指定LoaderOptimization為MultiDomain即可。比如,還是采用對Foo類型Foo類型(typeof(Foo))對象加鎖,這次我們在Main方法上應用了這樣的特性:[LoaderOptimization(LoaderOptimization.MultiDomain)]。輸出的結果就與對Int32類型對象加鎖一樣。

         1: [LoaderOptimization(LoaderOptimization.MultiDomain)]
         2: static void Main(string[] args)
         3: {
         4:     Action<ObjectLock> lockObj = objLock => objLock.Lock(typeof(Foo), 2000);
         5:     Action<ObjectLock> checkLock = objLock => objLock.CheckLock(typeof(Foo));
         6:  
         7:     Thread lockObjThread = new Thread(() => AppDomainContext.NewContext("Foo").Invoke<ObjectLock>(lockObj));
         8:     Thread checkLockThread = new Thread(() => AppDomainContext.NewContext("Bar").Invoke<ObjectLock>(checkLock));
         9:  
        10:     lockObjThread.Start();
        11:     Thread.Sleep(500);
        12:     checkLockThread.Start();
        13: }

      輸出結果:

         1: [Foo] Successfully lock the object.
         2: [Bar] The object is locked.

      又一個關于加鎖的注意:謹慎地對Type對象進行加鎖

      關于CLR內存管理一些深層次的討論[上篇]
      關于CLR內存管理一些深層次的討論[下篇]

      posted @ 2010-10-18 22:02  Artech  閱讀(12612)  評論(146)    收藏  舉報
      主站蜘蛛池模板: 国产综合av一区二区三区| 熟妇激情一区二区三区| 国产成人精品无人区一区| 中文字日产幕码三区国产| 欧美中文字幕无线码视频| 成人做爰www网站视频| 在线视频中文字幕二区| 99精品国产一区二区三区不卡| 又爽又黄又无遮掩的免费视频 | 国产成人午夜在线视频极速观看| 大色综合色综合网站| 黑森林福利视频导航| 又黄又无遮挡AAAAA毛片| 中文字幕亚洲人妻一区| 亚洲高请码在线精品av| 亚洲一区二区av高清| 挺进粗大尤物人妻中文字幕| 人妻少妇无码精品专区| 欧美成人精品三级网站视频| 国产稚嫩高中生呻吟激情在线视频| 精品久久欧美熟妇www| 91人妻无码成人精品一区91| 亚洲国产成人久久综合野外| 国产午精品午夜福利757视频播放| 特级做a爰片毛片免费看无码| 亚洲欧洲日产国码久在线| 粉嫩国产av一区二区三区| 亚洲中文无码手机永久| 巨熟乳波霸若妻在线播放| brazzers欧美巨大| 丰满少妇呻吟高潮经历| 男人猛躁进女人免费播放| 91精品国产麻豆国产自产| 国产亚洲精品俞拍视频| 国产黑色丝袜在线播放| 西西444www高清大胆| 国产乱子伦视频在线播放| 精品久久久久久久久午夜福利| 国内精品自在拍精选| 亚洲日本韩国欧美云霸高清| 精品无码国产污污污免费|