C# 使用綁定句柄來減少進程的記憶體耗用

黄舟
發布: 2017-02-13 11:32:49
原創
1885 人瀏覽過


許多應用程式中,綁定了一組類型(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,003Heap 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://www.php.cn/

許多應用程式中,綁定了許多應用程式中,綁定了一組類型中,綁定了一組類型中,綁定了一組類型中,綁定了(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,003Heap 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
登入後複製
登入後複製

以上就是C# 使用綁定句柄來減少進程的記憶體耗用的內容,更多相關內容請關注PHP中文網(www.php.cn)!


來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!