1. 程式人生 > 程式設計 >詳細分析c# 客戶端記憶體優化

詳細分析c# 客戶端記憶體優化

背景概述

C# 開發客戶端系統的時候,.net 框架本身就比較消耗記憶體資源,特別是xp 這種老爺機記憶體配置不是很高的電腦上執行,所以就需要進行記憶體上的優化,才能流暢的在哪些低端電腦上執行. 想要對C# 開發的客戶端記憶體優化需要了解以下幾個概念。

虛擬記憶體

這裡引用百度百科的概念:虛擬記憶體是計算機系統記憶體管理的一種技術。它使得應用程式認為它擁有連續的可用的記憶體(一個連續完整的地址空間),而實際上,它通常是被分隔成多個實體記憶體碎片,還有部分暫時儲存在外部磁碟儲存器上,在需要時進行資料交換。目前,大多數作業系統都使用了虛擬記憶體,如Windows家族的“虛擬記憶體”;Linux的“交換空間”等。

一句話概括虛擬記憶體既是使用磁碟,物理磁碟進行虛擬化出來的記憶體空間。

實體記憶體

實體記憶體(Physical memory)是相對於虛擬記憶體而言的。實體記憶體指通過實體記憶體條而獲得的記憶體空間,而虛擬記憶體則是指將硬碟的一塊區域劃分來作為記憶體。記憶體主要作用是在計算機執行時為作業系統和各種程式提供臨時儲存。常見的實體記憶體規格有256M、512M、1G、2G等,現如今隨著計算機硬體的發展,已經出現4G、8G甚至更高容量的記憶體規格。當實體記憶體不足時,可以用虛擬記憶體代替。在應用中,自然是顧名思義,物理上,真實存在的插在主機板記憶體槽上的記憶體條的容量的大小。看計算機配置的時候,主要看的就是這個實體記憶體。

GC 垃圾回收機制

簡介

C#中和Java一樣是一種系統自動回收釋放資源的語言,在C#環境中通過 GC(Garbage Collect)進行系統資源回收,在資料基本型別中介紹到,C#資料型別分為引用型別和值型別,

值型別儲存在Stack上,隨著函式的執行作用域執行完畢而自動出棧,所以這一型別的資源不是GC所關心 物件。GC垃圾回收主要是是指儲存在Heap上的資源。

.NET的GC機制有這樣兩個問題:

  • 首先,GC並不是能釋放所有的資源。它不能自動釋放非託管資源。
  • 第二,GC並不是實時性的,這將會造成系統性能上的瓶頸和不確定性。

GC並不是實時性的,這會造成系統性能上的瓶頸和不確定性。所以有了IDisposable介面,IDisposable介面定義了Dispose方法,這個方法用來供程式設計師顯式呼叫以釋放非託管資源。使用using語句可以簡化資源管理。

託管資源和非託管資源

上面介紹到,GC只釋放託管資源,那麼什麼是託管資源和費託管資源。

  • 託管資源 : 託管資源指的是.NET可以自動進行回收的資源,主要是指託管堆上分配的記憶體資源。託管資源的回收工作是不需要人工干預的,有.NET執行庫在合適呼叫垃圾回收器進行回收。
  • 非託管資源:非託管資源指的是.NET不知道如何回收的資源,最常見的一類非託管資源是包裝作業系統資源的物件,例如檔案,視窗,網路連線,資料庫連線,畫刷,圖示 等。這類資源,

垃圾回收器在清理的時候會呼叫Object.Finalize()方法。預設情況下,方法是空的,對於非託管物件,需要在此方法中編寫回收非託管資源的程式碼,以便垃圾回收器正確回收資源。

  • 總結:託管資源是釋放由GC來完成,釋放的時間吧不一定,一般是系統感覺記憶體吃緊,會進行緊急回收資源。一個物件想成為被回收,首先需要成為垃圾,GC是通過判斷物件及其子物件有沒有指向有效的引用,如果沒有GC就認為它是垃圾。垃圾回收機制通過一定的演算法得到哪些沒有被被引用、或者不再呼叫的資源,當這些垃圾達到一定的數量時,回啟動垃圾回收機制,GC回收實際上是呼叫了解構函式。垃圾回收機制意味著你不需要擔心處理不再需要的物件了。咱們關心的主要是非託管資源的釋放。垃圾回收時物件一共有三代 :0,1,2。每一代都有自己的記憶體預算,空間不足的時候會呼叫垃圾回收。為了提高效能都是按代回收,第0代超預算之後就回收第0代的物件,而存活下來的物件就提升為第1代,依次類推,而往往經過多次0代的垃圾回收才能回收一次第1代。

GC進行垃圾回收是系統決定的,下面是進行強制回收的執行程式碼(非特殊情況下不要使用此方法,會影響系統效率,削弱垃圾回收器中優化引擎的作用,而垃圾回收器可以確定執行垃圾回收的最佳時間)

//對所有代進行垃圾回收。
GC.Collect();
//對指定的代進行垃圾回收。
GC.Collect(int generation); 
//強制在 System.GCCollectionMode 值所指定的時間對零代到指定代進行垃圾回收。
GC.Collect(int generation,GCCollectionMode mode); 

關於 SetProcessWorkingSetSize 和記憶體釋放

在應用程式中,往往為了釋放記憶體等,使用一些函式,其實,對於記憶體操作函式要謹慎使用,比如大家常常想到的 SetProcessWorkingSetSize,其實對於windows來說,系統會自動在程式閒置時(如程式被最小化)釋放記憶體的,自己用記憶體釋放 時,往往會造成一些莫名的記憶體錯誤,造成自己的應用程式及系統不穩定。

SetProcessWorkingSetSize的作用

實體記憶體轉移到虛擬記憶體中

  • msdn解釋:使用這個函式來設定應用程式最小和最大的執行空間,只會保留需要的記憶體.當應用程式被閒置或系統記憶體太低時,作業系統會自動呼叫這個機制來設定應用程式的記憶體.應用程式也可以使用 VirtualLock 來鎖住一定範圍的記憶體不被系統釋放;當你加大執行空間給應用程式,你能夠得到的實體記憶體取決於系統,這會造成其他應用程式降低效能或系統總體降低效能,這也可能導致請求實體記憶體的操作失敗,例如:建立 程序,執行緒,核心池,就必須小心的使用該函式.也就是說,該函式不是節省記憶體,而是強制把程序的實體記憶體搬到虛擬記憶體中.

SetProcessWorkingSetSize 的劣勢

  • 危害:如果 SetProcessWorkingSetSize 函式被正常使用,是非常有用處的.但是為了矇騙使用者的眼睛,每秒,甚至幾十毫秒就把大量記憶體往虛擬記憶體裡面壓,就會帶來無可預計的危害.看看這篇文章怎麼 說:“因為他只是暫時的將應用程式佔用的記憶體移至虛擬記憶體,一旦,應用程式被啟用或者有操作請求時,這些記憶體又會被重新佔用.如果你強制使用該方法來設定 程式佔用的記憶體,那麼可能在一定程度上反而會降低系統性能,因為系統需要頻繁的進行記憶體和硬碟間的頁面交換.”

優化記憶體程式碼:

[DllImport("kernel32.dll")]
private static extern bool SetProcessWorkingSetSize(IntPtr proc,int min,int max);

private void FlushMemory()
{
  GC.Collect();
  GC.WaitForPendingFinalizers();
  if (Environment.OSVersion.Platform == PlatformID.Win32NT)
  {
    SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle,-1,-1);
  }
}

以上就是詳細分析c# 客戶端記憶體優化的詳細內容,更多關於c# 客戶端記憶體優化的資料請關注我們其它相關文章!