日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

的run代码_小心使用 Task.Run 续篇

發布時間:2025/3/12 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 的run代码_小心使用 Task.Run 续篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

關于前兩天發布的文章:為什么要小心使用 Task.Run,對文中演示的示例到底會不會導致內存泄露,給很多人帶來了疑惑。這點我必須向大家道歉,是我對導致內存泄漏的原因沒描述和解釋清楚,也沒用實際的示例證實,是我的錯。

但是,文中示例演示的 Task.Run 捕獲類成員的情況,確實會有內存泄漏的風險,我將在本文演示給大家看。

如果一個對象(或數據)不需要再使用了,但依然還一直占據內存空間,則視為內存泄漏。這一點大家觀點是一致的吧,那如何來檢測對象有沒有被回收呢?

我們知道,在 C# 中,實例對象被釋放回收,必然會執行析構函數。所以我們可以對一個類重寫其析構函數,如果該類的實例對象使用完后,強制執行 GC 回收,其析構函數依然不被執行,則說明 GC 沒有回收該對象。若 GC 后面一直不回收這個對象,則說明存在內存泄漏。

手動強制執行 GC 回收的代碼如下:

GC.Collect();GC.WaitForPendingFinalizers();GC.Collect();

這三句代碼可以確保 GC 把所有能搜索到的可回收對象清理干凈。注意:不推薦在生產環境這樣寫。

我們還是用 為什么要小心使用 Task.Run 這篇文章用到的示例,只是為了測試稍加修改了一下:

class?Program{ static?void?Main(string[] args) { Test(); // 對不需要再使用的資源強制回收 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); // 程序保活 while (true) { Thread.Sleep(100); } } static?void?Test() { var myClass = new MyClass(); myClass.Foo(); // 到這,myClass對象不需要再使用了 }}public?class?MyClass{ private?int _id; private List _list; public Task Foo() { return Task.Run(() => { Console.WriteLine($"Task.Run is executing with ID {_id}"); Thread.Sleep(100); // 模板耗時操作 }); } ~MyClass() { Console.WriteLine("MyClass instance has been colleted."); }}

我們在 myClass 對象使用完后,手動強制執行 GC 回收,運行結果如下:

我們看到 MyClass 的析構函數一直沒有執行,也就意味著它的實例一直沒有被回收。

現在我們修改 MyClass 類的 Foo 方法,改用本地(局部)變量試一試:

...public Task Foo(){ var localId = _id; return Task.Run(() => { Console.WriteLine($"Task.Run is executing with ID {localId}"); });}...

再運行看看效果:

這次我們可以看到,MyClass 的析構函數執行了,說明實例對象被回收了。

前后唯一區別是,前者在 Task.Run 的匿名方法中捕獲了類的成員,而后者使用了本地變量。前者出現了內存泄漏,后者避免了內存泄漏。

所以,在 Task.Run 的匿名方法中捕獲類的成員,確實有可能導致內存泄漏(注意是有可能而不是一定)。

那背后的原因是什么呢?我在上一篇文章是這樣解釋的:

私有成員 _id 被 Task.Run 的匿名方法捕獲使用,進而導致 MyClass 實例被引用。當外部使用完 MyClass 實例時,本該由 GC 回收的時候卻發現它還被其它資源引用著,所以 GC 認為該實例不應該被回收,也就可能永遠失去了被回收的機會。

這個解釋有很大的問題,至少給廣大讀者帶來了兩大疑惑:

  • 由于值類型是拷貝的方式賦值,所以捕獲的本地變量和類成員指向的是各自的值,對本地變量的捕獲不會影響到整個類。但如果把 _id 改為引用類型(如 String),那兩者指向的就是同一個對象值,那是不是意味著即便使用本地變量也還是無法避免內存泄漏的問題?
  • GC 第一次回收時發現 myClass 實例存在被捕獲的成員,則認為它不應該被回收。那當 Task.Run 執行完后, 被捕獲的成員也使用完了,GC 再次搜索時不就可以回收 myClass 對象嗎?只是晚了一些時間回收而已嘛。
  • 感謝善于思考提出疑惑的讀者們,為你們點贊。

    這兩大疑惑該如何解釋?后半部分我還沒寫完,大家可以先思考一下,我將在下一篇給大家解惑,望大家見諒。當然,我的解釋也不一定會是對的,希望大家帶著懷疑的態度和批判性思維來看我的文章,也請大家分享自己的理解和觀點。

    -

    精致碼農

    帶你洞悉編程與架構

    點頭像關注,不錯過網海相遇的緣分[比心]

    創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

    總結

    以上是生活随笔為你收集整理的的run代码_小心使用 Task.Run 续篇的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。