<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          小心使用 Task.Run 終篇解惑

          共 2451字,需瀏覽 5分鐘

           ·

          2020-12-09 00:38


          上一篇文章之后,這篇文章主要解答以下兩個疑惑:

          1. 由于值類型是拷貝的方式賦值,所以捕獲的本地變量和類成員是指向的是各自的值,對本地變量的捕獲不會影響到整個類。但如果把?_id?改為引用類型(如 String),那兩者指向的就是同一個對象值,那是不是意味著即便使用本地變量也還是無法避免內(nèi)存泄漏的問題?

          2. GC 第一次回收時發(fā)現(xiàn)?myClass?實例存在被捕獲的成員,則認為它不應該被回收。那當?Task.Run?執(zhí)行完后,GC 再次搜索時不就可以回收?myClass?對象嗎?只是晚了一些時間回收而已。

          為了方便理解,我再把昨天的關鍵代碼貼出來:

          public?class?MyClass
          {
          private?int _id;
          private List<string> _list;

          public Task Foo()
          {
          var localId = _id;
          return Task.Run(() =>
          {
          Console.WriteLine($"Task.Run is executing with ID {localId}");
          Thread.Sleep(100); // 模擬耗時操作
          });
          }
          }

          先來看第一個疑惑。經(jīng)實測,把?_id?改為?String?類型運行結果是和?int?一樣的,說明和值類型或引用類型無關。我的理解是這樣的:

          我們知道,引用類型的變量在聲明的時候就會在棧中分配一個空間,用來存放地址引用,而給它的賦值則存儲在托管堆中。雖然本地變量?localId?和類的成員?_id?的地址都指向的是托管堆中同一塊空間,但他們在棧中的地址卻分屬不同的作用域。所謂被捕獲就是被作用域捕獲,當一個作用域結束時,該作用域內(nèi)的成員的地址空間都會隨著一起被釋放。至于地址指向的托管堆中的字符串值,則不是作用域關心的事情。當該字符串值所在的空間沒有地址指向它時,就會被 GC 回收。有點抽象,但應該還好理解。

          再來看第二個疑惑。在此之前,我們先來了解一下 GC 的分代算法。

          當 CLR 試圖搜索不再使用的對象的時,它需要遍歷托管堆上的對象。隨著程序的持續(xù)運行,托管堆可能越來越大,如果要對整個托管堆進行垃圾回收,勢必會嚴重影響性能。所以,為了優(yōu)化這個過程,CLR 中使用了分代算法。

          簡單來說,分代算法就是把內(nèi)存中的資源劃分為三代:Gen 0、Gen 1、Gen 2,它們被 GC 遍歷的頻率依次從高到低。所有新創(chuàng)建的對象屬于 Gen 0,GC 掃描它的頻率最高。進行一次掃描后,處于 Gen 0 的不可回收對象就會被標記為 Gen 1。類似的,GC 掃描 Gen 1 時,如果 Gen 1 的對象依然不可回收,就會標記為 Gen 2。有點像馬太效應,資源停留在內(nèi)存時間越長,就越不容易被回收。

          Gen 2 的回收被稱為?Full GC。而 Full GC 只有在滿足一定的條件才會執(zhí)行,具體請閱讀這篇官方文檔:

          https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/notifications#full-garbage-collection

          也就是說,進入 Gen 2 的資源,若條件沒有達到,就會一直不被回收。

          理解了分代算法和 Full GC,第二個疑惑就迎刃而解了。第二個疑惑關鍵在三個時間點上:

          1. myClass?對象作用域結束的時間點

          2. GC 執(zhí)行回收的時間點

          3. Task.Run?匿名方法執(zhí)行完成的時間點

          如果程序執(zhí)行的時間點順序是:1、3、2,那么不會有內(nèi)存漏泄的問題,這點很容易理解。

          由于實際情況?Task.Run?一般為耗時操作(非耗時任務一般沒有必要使用?Task.Run),所以時間點的順序極有可能是:1、2、3。如果是此執(zhí)行的順序,那么 GC 在回收時就會因為?myClass?對象存在成員被引用而把它標記為 Gen 1。如果 Task.Run 耗時足夠長,?myClass?就可能會進入 Gen 2,進而可能很難被回收,甚至可能永遠不被回收。

          其實大部分場景,我們也不必過于小心,即使在?Task.Run?匿名方法捕獲了類的成員使該類的實例進入了 Gen 2,Gen 2 中留存的不再使用的資源也是有限的。根據(jù)官方文檔對 Full GC 的介紹(地址在前文),當 Gen 2 積累到一定的量時便滿足了執(zhí)行回收的條件,在 GC 下一次回收時便會回收 Gen 2 中不再使用的資源。當然,作為一個優(yōu)秀的程序員,我們還是得養(yǎng)成好的編碼習慣,不要在?Task.Run?中的匿名方法捕獲類的成員。

          最后,鄭重聲明,最近三篇關于小心使用 Task.Run 的文章皆屬我個人理解,知識水平有限,難免存在遺漏和錯誤。若有發(fā)現(xiàn),請大家不吝指正。


          往期精彩回顧




          【推薦】.NET Core開發(fā)實戰(zhàn)視頻課程?★★★

          .NET Core實戰(zhàn)項目之CMS 第一章 入門篇-開篇及總體規(guī)劃

          【.NET Core微服務實戰(zhàn)-統(tǒng)一身份認證】開篇及目錄索引

          Redis基本使用及百億數(shù)據(jù)量中的使用技巧分享(附視頻地址及觀看指南)

          .NET Core中的一個接口多種實現(xiàn)的依賴注入與動態(tài)選擇看這篇就夠了

          10個小技巧助您寫出高性能的ASP.NET Core代碼

          用abp vNext快速開發(fā)Quartz.NET定時任務管理界面

          在ASP.NET Core中創(chuàng)建基于Quartz.NET托管服務輕松實現(xiàn)作業(yè)調(diào)度

          現(xiàn)身說法:實際業(yè)務出發(fā)分析百億數(shù)據(jù)量下的多表查詢優(yōu)化

          關于C#異步編程你應該了解的幾點建議

          C#異步編程看這篇就夠了


          瀏覽 106
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩欧美在线资源 | 国产精品人妻熟女毛片av | 国产激情视频久久久久久久 | 激情自拍偷拍 | 亚洲欧美999 |