目錄
減少分配率
最重要的規則
縮短物件的生命週期
減少物件層次的深度
減少物件之間的引用
避免釘住物件(Pinning)
首頁 後端開發 C#.Net教程 編寫高效能 .NET的實例教學課程

編寫高效能 .NET的實例教學課程

Jun 25, 2017 am 09:08 AM
.net 程式碼 編寫 翻譯 高效能

減少分配率

這個幾乎不用解釋,減少了記憶體的使用量,自然就減少GC回收時的壓力,同時降低了記憶體碎片與CPU的使用量。你可以用一些方法來達到這個目的,但它可能會與其它設計相衝突。

你需要在設計物件時仔細檢查每個它並問自己:

  1. #我真的需要這個物件嗎?

  2. 這個欄位是我需要的嗎?

  3. 我能減少陣列的尺寸嗎?

  4. 我能縮小primitives的尺寸嗎(用Int32替換Int64,其它)?

  5. 這些對象,是否只有在極少數情況下,或只有初始化的時候才會被使用?

  6. 是否能將一些類別轉為結構體使他們在堆疊上分配或成為某個物件的一部分?

  7. 我是否分配了大量內存,但實際上只使用其中很小的一部分?

  8. 我可以從其它地方拿到相關資料?

小故事:在服務端一個回應請求的函數裡,我們發現在一次請求裡會分配一些比記憶體段要大的記憶體。這樣導致每次請求我們都會觸發一次完整的GC,這是因為CLR要求所有的0代物件都在一個記憶體段裡,目前分配的記憶體段滿了,就會開闢一個新的記憶體段,同時對原先的記憶體段做一次2代的回收。這不是一個好的實現,因為我們除了減少記憶體分配外別無它法。

最重要的規則

對於垃圾回收的高效能程式設計有一個基本規則,事實上也是程式碼設計的指導規則。

要收集的物件要麼在0代,要麼不存在
Collect objects in gen 0 or not at all.

#不同的是,你希望一個物件擁有極短的生命週期,在GC的時候永遠不要碰到它,或者,如果你做不到這一點,它們應該去2代,盡可能的快,永遠的呆在那,永遠不會被回收。這意味著你永遠保持對長生命週期物件的引用。通常,也意味著物件可重複使用,尤其是在大物件堆裡的物件。
GC每高一個世代的回收會比上一個世代更耗時。如果你想保持許多0,1代和少量的2代物件。即使開啟後台GC做2代做回收,也會消耗相當CPU運算量,你可能更願意將這部分的CPU消耗給應用程序,而不是GC。

Note 你可能聽過一個說法,每10次0代的回收會產生一次1代的回收,每10次1代的回收會產生1次2代的回收。這其實是不正確的,但你要明白,你要盡量產生多次快速的0代回收,以及少量的2代回收。

你最好避免進行1代回收,主要是因為已經從0代提升到1代的對象,會在這時候被轉入2代。 1代是物件進入2代的一個緩衝區。
理想情況下,你分配的每一個物件應該在下一次0代回收前結束生命週期。你可以測量兩次GC的時間間隔,並將其與應用程式裡物件的生命週期長度做對比。有關如何使用工具測量生命週期的信息,可以在本章結尾看到。
你可能不習慣這樣思考,但這規則切入了應用程式的方方面面,你需要經常思考它,在心態要做根本的轉變,這樣才能實現這個最重要的規則。

縮短物件的生命週期

一個物件的作用範圍越短,在下一個GC出現時,它被提升到下一代的機會就越小。一般來說,在你需要之前,不要創建物件。
同時,當物件創建的代價如此之高時,異常就可以在較早的時候創建,這樣不會幹擾到其他處理邏輯。
另外,你也要確保物件盡可能早的退出作用域。對於局部變量,你可以在最後一次使用後,甚至在方法結束前將其生命週期結束。你可一個用{}將程式碼包含起來,這不會對你的運行產生影響,但編譯器會認為在這個範圍的物件已經完成了他的生命週期,不再被使用了。如果需要呼叫物件的方法,盡量減少第一次和最後一次的時間間隔,以便GC儘早的回收物件。
如果物件關聯(引用)了一些會長時間保持的對象,則需要解除他們的引用關係。你可能會有更多的空值檢查(null判斷),這可能會讓程式碼變得更複雜。也會在物件的可用狀態(always having full state available)上與效率之間造成緊張關係,特別是調試的時候。
解決的一種方法是,將要清空的物件轉換為另一種方式存在,例如:日誌訊息,這樣在後面的偵錯時可以查詢到相關資訊。
另一個方法是為程式碼增加可設定選項(不解除物件之間的關係):執行程式(或執行程式裡特定的一個部分,例如一個特定的請求),在這個模式中沒有解除對象引用關係,而是盡可能讓物件一直保持方便調試。

減少物件層次的深度

如本章開頭所述,GC在回收時會順著物件的參考關係進行遍歷。在伺服器GC模式,GC會以多執行緒方式執行,但如果一個執行緒需要處理一個物件層次很深,則所有已經處理完的執行緒都需要等待這個執行緒完成處理後才能退出。在今後的CLR版本裡,你可以不用太關注這個問題,GC在多執行緒執行時會採用更好的標記演算法來做負載平衡。但如果你物件層次很深,這個問題還是要注意一下的。

減少物件之間的引用

這與上節的深度有關,但也有一些其它的因素。
一個物件如果引用了很多物件(數組,List吧),那它將花很多時間在遍歷物件上。是GC造成長時間的問題,因為它有一個複雜的關係圖。
另一個問題是,如果無法輕鬆的確定物件有多少引用關係,那麼你就無法準確的預測物件的生命週期。減少這種複雜度是相當有必要的,它不但可以讓程式碼更健壯,同時也方便調試以及獲得更好的效能。
另外,也要注意不同世代物件之間的引用也會導致GC的效率低下,特別是舊物件對新物件的引用。例如,如果2代對像在0代對象裡有引用關係,那麼每次發生0代的GC時,也需要掃描部分2代對象,看看他們是否仍保持在0代對象的引用上。雖然這不是一次完整的GC,但它仍然是不要的工作,你應該盡量避免這種情況。

避免釘住物件(Pinning)

釘住物件可以保證從託管程式碼傳送資料到本機程式碼的安全性。常見的有數組和字串。如果你的程式碼不需要與本地程式碼做交互,則不用考慮它的效能開銷。
釘住物件就是讓物件在垃圾回收(壓縮階段)時無法移動他。雖然釘住物件不會造成太多開銷,但它會妨礙到GC的回收操作,增加記憶體碎片的可能性。 GC在回收時會記錄物件的位置,以便在重修分配時利用它們之間的空間,但如果釘住的物件很多,會導致記憶體碎片的增加。
釘可以是顯示的也可以使隱式的。顯示的是使用GCHandle時用GCHandleType.Pinned參數進行設置,或在unsafe模式下使用 fixed 關鍵字。使用fixed關鍵字和GCHandle的差異在於是否會顯示呼叫Dispose方法。使用fixed雖然很方便,但是不能在非同步情況下使用,但還是可以建立一個句柄物件(GCHandle),在回呼時傳回並處理。
隱式的釘住物件比較常見,但也更難排查,也更難移除。最明顯的例子就是透過平台呼叫(P/Invoke)將物件傳遞給非託管程式碼。這不只是你的程式碼—--你經常呼叫的一些託管API,其實也是會呼叫本機程式碼,也會將物件釘住。
CLR也會將自己的一些資料釘住,但這通常不需要你來關心。
理想情況下,你應該盡可能的不要釘住對象。如果不能做到,那麼遵循先前的重要規則,盡可能讓這些被釘的對象儘早釋放。如果物件只是簡單的被釘住後釋放,那麼就不會有多少機會影響回收操作。你同時也要避免同時釘住很多個物件。被釘的對像被交換到2代或在LOH裡分配會稍微好些。根據這個規則,你可以在大物件堆上分配一個大的緩衝區,並根據實際需要自己對緩衝區做管理。或在小物件對上分配緩衝區,然後在釘住他們之前,使他們升級到2代。這樣比你直接將對象釘在0代上要好。

以上是編寫高效能 .NET的實例教學課程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

edge瀏覽器附的翻譯網頁不見了怎麼辦? edge瀏覽器附的翻譯網頁不見了怎麼辦? Mar 14, 2024 pm 08:50 PM

edge瀏覽器自帶了翻譯功能讓用戶們可以隨時隨地的進行翻譯,為用戶們帶來了極大的便利,可也有不少的用戶們表示自帶的翻譯網頁不見了,那edge瀏覽器自帶的翻譯網頁不見了怎麼辦?下面就讓本站來介紹一下edge瀏覽器自備的翻譯網頁不見了怎麼恢復方法吧。  edge瀏覽器自帶的翻譯網頁不見了怎麼恢復方法  1、檢查是否啟用了翻譯功能:在Edge瀏覽器中,點擊右上角的三個點圖標,然後選擇「設定」選項。在設定頁面的左側,選擇“語言”選項。確保“翻譯&rd

藍色畫面代碼0x0000001怎麼辦 藍色畫面代碼0x0000001怎麼辦 Feb 23, 2024 am 08:09 AM

藍屏代碼0x0000001怎麼辦藍屏錯誤是電腦系統或硬體出現問題時的一種警告機制,代碼0x0000001通常表示出現了硬體或驅動程式故障。當使用者在使用電腦時突然遇到藍色畫面錯誤,可能會感到驚慌失措。幸運的是,大多數藍色畫面錯誤都可以透過一些簡單的步驟來排除和處理。本文將為讀者介紹一些解決藍屏錯誤代碼0x0000001的方法。首先,當遇到藍色畫面錯誤時,我們可以嘗試重

看片不怕沒字幕!小米宣布小愛翻譯即時字幕上線日韓文翻譯 看片不怕沒字幕!小米宣布小愛翻譯即時字幕上線日韓文翻譯 Jul 22, 2024 pm 02:11 PM

7月22日消息,今日,小米澎湃OS官微宣布小愛翻譯迎來升級,實時字幕新增日韓語翻譯,無字幕視頻、直播會議實時轉錄翻譯。面對面同聲傳譯支持12種語言互譯,包括中文、英語、日語、韓語、俄語、葡萄牙語、西班牙語、義大利語、法語、德語、印尼語、印地語。以上功能目前僅支援以下三款新機:小米MIXFold4小米MIXFlipRedmiK70至尊版據悉,2021年,小愛同學AI字幕宣布加入日文、韓文翻譯。 AI字幕採用小米自研同聲傳譯技術,提供更快速、穩定且精準的字幕閱讀體驗。 1.官方稱,小愛翻譯不僅能在影音場

解決代碼0xc000007b錯誤 解決代碼0xc000007b錯誤 Feb 18, 2024 pm 07:34 PM

終止代碼0xc000007b在使用電腦時,有時會遇到各種各樣的問題和錯誤代碼。其中,終止代碼最為令人困擾,尤其是終止代碼0xc000007b。這個程式碼表示某個應用程式無法正常啟動,給用戶帶來了不便。首先,我們來了解終止碼0xc000007b的意思。這個程式碼是Windows作業系統的錯誤代碼,通常發生在32位元應用程式嘗試在64位元作業系統上執行時。它表示應

GE通用遠端程式碼可在任何裝置上編程 GE通用遠端程式碼可在任何裝置上編程 Mar 02, 2024 pm 01:58 PM

如果您需要遠端編程任何設備,這篇文章會為您帶來幫助。我們將分享編程任何設備的頂級GE通用遠端代碼。通用電氣的遙控器是什麼? GEUniversalRemote是一款遙控器,可用於控制多個設備,如智慧電視、LG、Vizio、索尼、藍光、DVD、DVR、Roku、AppleTV、串流媒體播放器等。 GEUniversal遙控器有各種型號,具有不同的功能和功能。 GEUniversalRemote最多可以控制四台設備。頂級通用遙控器代碼,可在任何裝置上編程GE遙控器配備一組代碼,使其能夠與不同設備配合。您可

如何使用Copilot產生程式碼 如何使用Copilot產生程式碼 Mar 23, 2024 am 10:41 AM

身為一名程式設計師,對於能夠簡化程式設計體驗的工具,我感到非常興奮。借助人工智慧工具的幫助,我們可以產生演示程式碼,並根據需求進行必要的修改。在VisualStudioCode中新引入的Copilot工具讓我們能夠創建具有自然語言聊天互動的AI生成程式碼。透過解釋功能,我們可以更好地理解現有程式碼的含義。如何使用Copilot產生程式碼?要開始,我們首先需要取得最新的PowerPlatformTools擴充。要實現這一點,你需要進入擴充頁面,搜尋“PowerPlatformTool”,然後點擊Install按鈕

谷歌瀏覽器自備翻譯失效如何解決? 谷歌瀏覽器自備翻譯失效如何解決? Mar 13, 2024 pm 08:46 PM

  瀏覽器通常都會自備翻譯功能,這樣在瀏覽外文網站時就不用擔心看不懂啦!谷歌瀏覽器也不例外,但是有用戶發現自己打開谷歌瀏覽器的翻譯功能時沒有反應,失效了,這該如何處理?可以試試小編找到的最新解決方案。  操作教學:  點選右上角三個點,點選設定。  點擊新增語言,新增英文和中文,並為他們做出下面設置,英文設定詢問是否翻譯此語言網頁,中文設定以這種語言顯示網頁,並且中文要移至頂部,才能設定為預設語言。  如果你打開網頁沒有彈出是否翻譯選項,右鍵選擇翻譯中文,ok。

編寫C語言中計算冪函數的方法 編寫C語言中計算冪函數的方法 Feb 19, 2024 pm 01:00 PM

如何在C語言中編寫乘方函數乘方(exponentiation)是數學中常用的運算,表示將一個數自乘若干次的操作。在C語言中,我們可以透過寫一個乘方函數來實現這個函數。以下將詳細介紹如何在C語言中編寫乘方函數,並給出具體的程式碼範例。確定函數的輸入和輸出乘方函數的輸入通常包含兩個參數:底數(base)和指數(exponent),輸出為計算得到的結果。因此,我們

See all articles