關於LFH堆 .

來源:互聯網
上載者:User

這段時間項目中遇到了記憶體片段的問題,在雙核四G的機器上,明明進程的虛擬記憶體只用了500M左右,但new卻會拋出bad_alloc異常,用process explorer查看進程的記憶體的使用方式,發現雖然virtual memory僅為500M左右,但已指派的地址空間virtual size卻已將近2G了,然後又用vmmap查看進程地址空間分配情況,發現堆記憶體配置佔用比很高,而且記憶體位址中,總是兩個reserve中總是夾著一個commit,很顯然,這是記憶體位址空間嚴重片段的表徵。記憶體片段的問題慣常的解決方案是使用記憶體池,最簡單的記憶體池就是預先分配好大塊連續記憶體,然後使用時拆分成最頻繁使用固定大小的小塊記憶體。但是我們這個項目中由於用到一些比較大且較複雜的開源庫,要想定位相關代碼的位置,無論從時間和精力上都比較困難。所以,我決定從執行階段程式庫標準記憶體配置常式上著手。原本的方法是實現一個記憶體池,然後替換掉crt標準的記憶體配置常式。然而,閱讀crt記憶體相關代碼發現,malloc實際是通過windows堆api實現的,我們知道windows堆架構分為前端和後端兩部分,前端的堆分為兩種,一種是旁查列表實現的效能較高的LAL堆,還有一種是LFH堆。LFH堆顧名思義就是底片段堆,而LFH對於頻繁分配小記憶體塊的情形可以有效降低記憶體片段。而crt中使用的crt堆預設是LAL堆,於是抱著姑且一試的心態,我將crt堆設成了LFH堆,再次運行程式,驚喜的發現虛擬記憶體地址空間的利用效率接近100%,原本進程中只能儲存500個會話,現今可以儲存5000個會話,足以滿足項目需求。下面是我寫的一個簡單設定LFH堆類型的代碼:

[cpp]
view plaincopyprint?
  1. BOOL SetLowFragmentHeaps()  
  2. {  
  3.  enum {  
  4.         LFHHeap = 2  
  5.     };  
  6.   
  7.     DWORD   dwHeapNum    = GetProcessHeaps(0, NULL);  
  8.     HANDLE* pHeapHandles = new HANDLE[dwHeapNum];  
  9.     DWORD   dwNum        = GetProcessHeaps(dwHeapNum, pHeapHandles);  
  10.   
  11.     ULONG   lHeapType    = LFHHeap;  
  12.     BOOL    bSuccess     = TRUE;  
  13.     HANDLE  hCrtHeap     = (HANDLE)_get_heap_handle();  
  14.   
  15.     while ( --dwNum )  
  16.     {     
  17.         BOOL bRet = HeapSetInformation( pHeapHandles[dwNum],   
  18.                                         HeapCompatibilityInformation,  
  19.                                         &lHeapType, sizeof(lHeapType) );  
  20.         // 對於crt堆,必須設為LFH堆!   
  21.         if ( !bRet && hCrtHeap == pHeapHandles[dwNum] )  
  22.         {  
  23.             bSuccess = FALSE;  
  24.             break;  
  25.         }  
  26.     }  
  27.   
  28.     delete[] pHeapHandles;  
  29.     return bSuccess;  
  30. }  
BOOL SetLowFragmentHeaps(){ enum {        LFHHeap = 2    };    DWORD   dwHeapNum    = GetProcessHeaps(0, NULL);    HANDLE* pHeapHandles = new HANDLE[dwHeapNum];    DWORD   dwNum        = GetProcessHeaps(dwHeapNum, pHeapHandles);    ULONG   lHeapType    = LFHHeap;    BOOL    bSuccess     = TRUE;    HANDLE  hCrtHeap     = (HANDLE)_get_heap_handle();    while ( --dwNum )    {           BOOL bRet = HeapSetInformation( pHeapHandles[dwNum],                                         HeapCompatibilityInformation,                                        &lHeapType, sizeof(lHeapType) );        // 對於crt堆,必須設為LFH堆!        if ( !bRet && hCrtHeap == pHeapHandles[dwNum] )        {            bSuccess = FALSE;            break;        }    }    delete[] pHeapHandles;    return bSuccess;}

最後談一下對自訂記憶體池的看法,很多人(包括之前的我)都一直認為要想實現高效的記憶體配置,就得自己實現一個記憶體池,潛意識裡覺得系統預提供的設施不足以滿足我們的效能需求,但是就我遇到的所有情形而言,系統的提供設施(無論是鎖還是記憶體池或是其他)往往要優於自己的所謂的高效實現,經過百般調優的系統設施在絕大多數情形下足以滿足我們的需求,所以當有系統為我們提供好高效健壯的實現,又何必要自己重新發明輪子呢?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.