C#效率優化(3)-- 使用foreach時避免裝箱

来源:https://www.cnblogs.com/minotauros/archive/2019/03/22/10577149.html
-Advertisement-
Play Games

Introduction: ※本文不是在描述舊版本Unity中mono編譯器導致的foreach語句額外裝箱錯誤 博主是一名Unity 3D游戲開發者,游戲使用C#+lua開發,最近在優化C#代碼時,發現了一處使用foreach不恰當的地方,其結果是造成了每幀近3k的GC Alloc,如此高頻率的G ...


Introduction:

  ※本文不是在描述舊版本Unity中mono編譯器導致的foreach語句額外裝箱錯誤

  博主是一名Unity 3D游戲開發者,游戲使用C#+lua開發,最近在優化C#代碼時,發現了一處使用foreach不恰當的地方,其結果是造成了每幀近3k的GC Alloc,如此高頻率的GC堆記憶體分配,會導致垃圾回收的調用更加頻繁,從而影響游戲性能,而這隻需要簡單的修改即可避免;

  ※使用.Net 2.0的Unity版本,如果是較新的.Net 4.x版本,由於FCL實現修改,本文中48->56

   原始聲明代碼如下:

private readonly IDictionary<int, MyClass> mDic = new Dictionary<int, MyClass>();

  在每幀邏輯裡面,會多次對其進行遍歷,遍歷代碼如下:

foreach(var keyValuePair in mDic)
{
    //do...
}

  通過Unity自帶的Profiler分析,可以發現其導致的GC Alloc:

Body:

  通過上面的Profiler可以發現此時foreach語句實際上調用的是Dictionary定義中隱式實現的IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()方法,該方法的聲明如下:

IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
{
    return new Enumerator(this, Enumerator.KeyValuePair);
}

   其中,Enumerator是在Dictionary類中定義的嵌套結構類型:

  結構類型隱式轉換為介面類型時會發生裝箱,對於該Enumerator類型,其裝箱後大小為16(開銷位元組)+8(欄位dictionary)+8(欄位next+stamp)+16(欄位current:8(int位元組對齊)+8)=48位元組,調用29次即產生48*29=1392位元組的堆記憶體分配,這符合我們看到Profiler裡面看到的GC Alloc;

  為瞭解決這個問題,只需要將變數聲明時改為Dictionary即可,不使用介面類型的變數,即:

private readonly Dictionary<int, MyClass> mDic = new Dictionary<int, MyClass>();

  此時,在對mDic進行foreach迴圈時,就會調用Dictionary<TKey,TValue>.GetEnumerator()方法,該方法返回值類型即結構類型的Enumerator,避免了裝箱操作:

One more thing:

  這裡可能很多人有個誤解,即foreach是只能對實現了IEnumerable或IEnumerable<T>的類型對象進行遍歷,其實不然,foreach語句還可以對滿足以下條件的任何類型的對象進行遍歷:

  實現了可訪問的GetEnumerator()方法,且該方法的返回值類型符合:包含可訪問的Current屬性和bool MoveNext()方法;

Conclusion:

  這樣就知道了,.Net框架類庫提供的泛型集合類型都實現了這樣的方法,因此可以放心對泛型集合進行foreach遍歷,而不產生堆記憶體的分配,也因此,我們在使用這些類型時,儘量避免直接對其介面類型的變數進行遍歷;

 


如果您覺得閱讀本文對您有幫助,請點一下“推薦”按鈕,您的認可是我寫作的最大動力!

作者:Minotauros
出處:https://www.cnblogs.com/minotauros/

本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。


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

-Advertisement-
Play Games
更多相關文章
  • 使用DSAPI實現PNG異形窗體,註意,該窗體為層樣式窗體,以PNG或32位帶透明通道的圖像合成到屏幕,此方法不會觸發窗體的重繪,故原窗體(包括其子控制項)均不會顯示,如果需要更新畫面,需要重新用代碼等繪製好一張PNG圖片然後再次調用該方法。 示例素材 運行效果 ...
  • 效果圖 部分代碼 本演示項目源代碼請到QQ群文件下載 ...
  • 通常,說到Hook鍵盤滑鼠,總需要一大堆代碼,涉及各種不明白的API.而在DSAPI中,可以說已經把勾子簡化到不能再簡化的地步.甚至不需要任何示例代碼即會使用.那麼如何實現呢? 註意上面帶了WithEvent. 寫完上面那句後,即可選擇該HK,然後通過事件列表裡選擇相應的事件編寫你需要的功能即可.支 ...
  • 本文介紹了Taurus新版本V2.3的新功能及基礎用法,包括Require、Token等屬性,還有增強的標簽功能,集成的許可權驗證功能,關鍵還有WebAPI文檔生成功能。 ...
  • 一丶前言 下麵是本人對於IOC容器的一些個人理解,希望能幫到初學者認識IOC,如有理解得不對的地方歡迎指正,也讓我學學。 二丶IOC是什麼,它是幹嘛的? IOC只是一種編程思想,不局限於任何一種語言,任何語言都可以實現這種編程思想。它的設計思想是想把創建對象,管理對象生命周期,程式集之間的解耦的工作 ...
  • 我特喵的,見鬼了。 幾個相同的Tabpage中添加相同toolStrip控制項,每次都是第二個Tabpage中的消失,但是查看設計器下麵又顯示控制項存在,點擊也會出現,運行後就沒有了,真的是奇怪。 最後經多方搜索彙總,讀出結論是他喵的Vs2010的問題只需去*designer.cs 中去把 this.t ...
  • 一.概述 接著上篇的WebAppIdentityDemo項目,將自定義用戶數據添加到Identity DB,自定義擴展的用戶數據類應繼承IdentityUser類, 文件名為Areas / Identity / Data / {項目名稱}User.cs。自定義的用戶數據模型屬性需要使用[Person ...
  • 在Smobiler的開發中,控制項或組件及客戶端功能都是通過事件或委托來進行處理的。 Smobiler是基於非同步非阻塞的方式來運行的 下麵我們分別對Windows的和Smobiler的MessageBox的處理方法來舉例說明。 Windows的MessageBox方法 l 開發過Windows的都比較 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...