C# 使用繫結控制程式碼來減少程式的記憶體耗用
許多應用程式中,繫結了一組型別(Type)或者型別成員(從MemberInfo派生),並將這些物件儲存在某種形式的一個集合中。以後,會搜尋這個集合,查詢特定的物件,然後呼叫這個物件。這是一個很好的機制,但是有個小問題:Type和MemberInfo派生的物件需要大量的記憶體。如果一個應用程式容納了太多這樣的類,但只是偶爾用一下它們,應用程式的記憶體就會急劇增長,對應用程式的效能產生影響。
在內部,CLR用一種更精簡的形式來表示這種資訊。CLR之所以為應用程式建立這些物件,只是為了簡化開發人員的工作。CLR在執行時並不需要這些大物件。如果需要快取大量Type和MemberInfo派生物件,開發人員可以使用執行時控制程式碼(runtime handle)來代替物件,從而減少工作集(佔用的記憶體)。FCL定義了3個執行時控制程式碼型別(都在System名稱空間中),RuntimeTypeHandle,RuntimeFieldHandle,RumtimeMethodHandle。三個型別都是值型別,他們只包含了一個欄位,也就是一個IntPtr;這樣一來,這些型別的例項就相當省記憶體。ItPtr欄位是一個控制程式碼,它引用了AppDomain的Loader堆中的一個型別,欄位或方法。轉換方法:
- Type→RuntimeTypeHandle,通過查詢Type的只讀欄位屬性TypeHandle。
- RuntimeTypeHandle→Type,通過呼叫Type的靜態方法GetTypeFromHanlde。
- FieldInfo→RuntimeFieldHandle,通過查詢FieldInfo的例項只讀欄位FieldHandle。
- RuntimeFieldHandle→FieldInfo,通過呼叫FieldInfo的靜態方法GetFieldFromHandle。
- MethodInfo→RuntimeMethodHandle,通過查詢MethodInof的例項只讀欄位MethodHandle。
- RuntimeMethodHandle→MethodInfo,通過呼叫MethodInfo的靜態方法GetMethodFromHandle。
下面的示例獲取許多的MethodInfo物件,把它們轉化成RuntimeMethodHandle例項,並演示轉換前後的記憶體差異。
private void UseRuntimeHandleToReduceMemory()
{
Show("Before doing anything");
//從MSCorlib.dll中地所有方法構建methodInfos 物件快取
List<MethodBase> methodInfos = new List<MethodBase>();
foreach (Type t in typeof(object).Assembly.GetExportedTypes())
{
if (t.IsGenericType) continue;
MethodBase[] mbs = t.GetMethods(c_bf);
methodInfos.AddRange(mbs);
}
//顯示當繫結所有方法之後,方法的個數和堆的大小
Console.WriteLine("# of Methods={0:###,###}", methodInfos.Count);
Show("After building cache of MethodInfo objects");
//為所有MethodInfo物件構建RuntimeMethodHandle快取
List<RuntimeMethodHandle> methodHandles = new List<RuntimeMethodHandle>();
methodHandles = methodInfos.ConvertAll<RuntimeMethodHandle>(m => m.MethodHandle);
Show("Holding MethodInfo and RuntimeMethodHandle");
GC.KeepAlive(methodHandles);//阻止快取被過早垃圾回收
methodInfos = null;//現在允許快取垃圾回收
Show("After freeing MethodInfo objects");
methodInfos = methodHandles.ConvertAll<MethodBase>(r => MethodBase.GetMethodFromHandle(r));
Show("Size of heap after re-creating methodinfo objects");
GC.KeepAlive(methodHandles);//阻止快取被過早垃圾回收
GC.KeepAlive(methodInfos);//阻止快取被過早垃圾回收
methodInfos = null;//現在允許快取垃圾回收
methodHandles = null;//現在允許快取垃圾回收
Show("after freeing MethodInfo and MethodHandle objects");
}
結果如下:
Heap Size = 114,788 - Before doing anything
# of Methods=10,003
Heap Size = 2,205,652 - After building cache of MethodInfo objects
Heap Size = 2,245,744 - Holding MethodInfo and RuntimeMethodHandle
Heap Size = 2,171,976 - After freeing MethodInfo objects
Heap Size = 2,327,516 - Size of heap after re-creating methodinfo objects
Heap Size = 247,028 - after freeing MethodInfo and MethodHandle objects
本文整理自《NET CLR via C#》
作者:jiankunking 出處:http://blog.csdn.net/jiankunking
相關文章
- lms程式耗用大量記憶體記憶體
- 使用MVVM減少控制器程式碼實戰(減少56%)MVVM
- Effective C#:儘量減少記憶體垃圾C#記憶體
- 使用String.intern減少記憶體使用記憶體
- 通過減少記憶體使用改善.NET效能記憶體
- 減少.NET應用程式記憶體佔用的一則實踐記憶體
- curl 中減少記憶體分配操作記憶體
- win10系統下如何減少RAM記憶體使用Win10記憶體
- 看我用AspectJ切切切程式碼來減少工作量
- python使用迭代生成器yield減少記憶體佔用的方法Python記憶體
- 字串池化,減少1/3記憶體佔用字串記憶體
- 選擇合適Redis資料結構,減少80%的記憶體佔用Redis資料結構記憶體
- 編寫良好的程式碼:如何減少程式碼的認知負荷
- 減少程式碼中該死的 if else 巢狀巢狀
- 谷歌Chrome瀏覽器引入省記憶體/省電模式:減少記憶體佔用谷歌Chrome瀏覽器記憶體模式
- 程式中減少使用 if 語句的方法集錦
- 程式中減少使用if語句的方法集錦
- 微軟的HotSpot C2可減少15%堆記憶體分配微軟HotSpot記憶體
- 谷歌改善 Chrome 記憶體安全:通過 heap scanning 演算法減少 C++ 程式碼庫安全漏洞谷歌Chrome記憶體演算法C++
- 論減少程式碼中return語句的騷操作
- 減少C++程式碼編譯時間的方法C++編譯
- mimalloc記憶體分配程式碼分析記憶體
- 使用 Node.js Stream API 減少伺服器端記憶體消耗的一個具體例子Node.jsAPI伺服器記憶體
- 減少Spring Boot的JVM記憶體佔用的Docker三種配置Spring BootJVM記憶體Docker
- 淺析C#程式設計中的記憶體管理C#程式設計記憶體
- 使用Egret外掛壓縮程式碼包體積,減少請求數量的實戰教程
- python定時爬蟲啟用時如何減少記憶體?Python爬蟲記憶體
- Optional簡化空值判斷,減少程式碼中的if-else程式碼塊
- Oracle例項的程式結構和記憶體結構Oracle記憶體
- php簡單使用shmop函式建立共享記憶體減少伺服器負載PHP函式記憶體伺服器負載
- 優雅地減少redux請求樣板程式碼Redux
- C#遍歷窗體控制元件程式碼,遍歷窗體所有按鈕控制元件程式碼C#控制元件
- Oracle體系結構:記憶體結構和程式結構(轉)Oracle記憶體
- js儘量減少程式碼重複執行的次數JS
- Linux記憶體點滴:使用者程式記憶體空間Linux記憶體
- [Virtualization]ESXi體系結構與記憶體管理(二)控制記憶體分配記憶體
- [Virtualization]ESXi體系結構與記憶體管理(三)控制記憶體分配記憶體
- 配置Tree Shaking來減少JavaScript的打包體積JavaScript