記憶體 Clerk (Memory Allocator)

來源:互聯網
上載者:User

標籤:webkit   記憶體管理   malloc   heap   


對於大多數開發人員而言,系統的記憶體配置就是一個黑盒子,就是幾個API的調用。有你就給我,沒有我就想別的辦法。來UC前,我就是這樣認為的。實際深入進去時,才發現這個領域裡也是百家爭鳴,非常熱鬧。有作業系統層面的記憶體 Clerk(Memory Allocator),有應用程式層面的,有為即時系統設計的,有為服務程式設計的。但他們的目的確認一樣的,平衡記憶體配置的效能和提高記憶體使用量的效率。


從瀏覽器開發的角度看,手機記憶體的增長速度相對於網頁內容的增長仍然只是溫暖水平,像Android這樣的用記憶體大戶更要算計著用。最近因為工作原因,涉及到了小記憶體 Clerk,所以做了一些粗淺的學習,沒有完整的閱讀代碼,也沒有進行透徹的測試,只是寫個總結以及相關的文檔放在這裡,備查。


記憶體配置的現實問題


首先通常使用的記憶體 Clerk,即malloc/free函數並不是系統提供的,而是C標準庫提供的。也被稱為動態記憶體分配器。分配器從作業系統拿記憶體(虛擬記憶體)時是以頁為單位(通常是4KB,調用sbrk或mmap), 然後再自行管理。


上面也提到了,記憶體 Clerk面對的是兩個核心問題: 效能和效能(或稱為輸送量Throughoutput)。 前者保證隨時有記憶體可用,後者保證服務時間短、不拖後腿。


對於一個系統進程而言,面對OOM(Out Of Memory)問題,排除程式使用記憶體的Bug外,會有兩個原因:
  1.系統真的沒有記憶體可用了。


  2.記憶體配置浪費了大量空間,雖然有大量零散的可用空間,卻無法合并提供出來使用。 前者才是真正的OOM, 後者就是記憶體片段(Fragmentation)問題了。


libc裡的malloc遇到沒有分配記憶體失敗時,預設會abort掉進程,也就是崩掉(CRASH)了。如果系統支援mallopt就有機會改變這個行為,可惜Android還沒有支援。

瀏覽器在載入、解析、渲染頁面的時候,會分配大量的小對象,看張圖就明白了:


中模軸為對象大小,縱軸則為申請分配的次數。如果記憶體都以頁為單位申請,就簡單,也就不需要分配器。就是那些小對象,佔用不多,使用頻繁,很容易造成頁內無法再繼續使用的片段(Internal Fragmentation)。


對於效能,記憶體配置是次於I/O的一個瓶徑。雖然絕大多數情況下都相安無事,但記憶體 Clerk有一個重要的指標,即上限(bounded limits)。雖然平均值看起很好,但一旦遇到最壞的情況(wrost case)時,能不能保證效能?特別是多線程下,記憶體配置、釋放的效能常常受到加鎖的影響。有些分配器(如ptmalloc)過於考慮效能,而無法使線程間的記憶體共用,各自佔去一塊,反而降低了記憶體使用量的效率。


這些問題一直存在,不同的人針對不同的情境設計出了不同的分配器演算法(DSA, Dynamic Storage Algorithms, 是以應用的角度來看的),而且幾乎每一個都說自己比別人強。比如:
   1. dlmalloc/ptmalloc/ptmallocX C標準庫提供的分配器, 也是應用程式預設使用的malloc/free等函數。
   2. tcmalloc 出自Google, WebKit/Chrome中應用。
   3. bmalloc 畢竟Chrome和WebKit越走越遠,所以Apple在WebKit最新代碼(2014-04)裡提供了新的分配器,號稱遠遠超過 TCMalloc, 至少是在效能上。
   4. jemalloc 原本是為FreeBSD開發的,後來Firefox瀏覽器和FaceBook的服務端都加以應用,它自身也在這些應用中得到了大幅提升。
   5. Hoard 一個專為多線程最佳化的分配器, 作者是大學教授,有一些獨特的技術。Mac OS X中的malloc就有參考其實現進行最佳化。

*WebKit另外專為Render Object提供了一個所謂的Plain Old Data Areana的類,也算是一個Memory Pool的實現(PODIntervalTree, PODArena)。



核心思想和演算法


分配器這麼多,其核心思想相似,只是差在演算法和metadata儲存上。附13提供的論文中有比較全面的總結,可以翻看一下。


記憶體 Clerk的核心思想概括起來三條:


1. 準系統:首先將記憶體區(Memory Pool)以最小單位(chunk)定義出來,然後區分對象大小分別管理記憶體,小記憶體分成若干類(size class),專門用來分配固定大小的記憶體塊,並用一個表管理起來,降低內部片段(internal fragmentation)。大記憶體則以頁為單位管理, 配合小對象所在的頁,降低片段。設計一個好的儲存方案,即metadata的儲存,減少對記憶體的佔用。同時最佳化記憶體資訊的儲存,以使對每個size class或大記憶體地區的訪問的效能最優且有上限(bounded limits)。


比如dlmalloc定義的是一個個bins(同size class)來儲存不同大小的記憶體塊:

     
2. 回收及預測功能: 當釋放記憶體時,要能夠合并小記憶體為大記憶體,根據一些條件,該保留的就保留起來,在下次使用時可以快速的響應。不需要保留時,則釋放回系統,避免長期佔用。


3. 最佳化多線程下效能問題:針對多線程環境下,每個線程可以獨立佔有一段記憶體區間,被稱為TLS(Thread Local Storage),這樣線程內操作時可以不加鎖,提高效能。是MSDN上貼出的關於TLS的原理圖,可以參考:

        


*另外測試載入器也是必不可少,比如tcmalloc的heap profile, jemalloc則結合valgrind。


上面這些思路對於各個分配器而言基本是一致,但具體如何組織size classes, 如果以一個固定步長,必將形成一個巨大且效率低下的表,原因參考第一張圖就明白了。另外還有如何定位記憶體塊? 如何解決多線程下的false cache line問題? 不同的分配器使用了不同的演算法和資料結構來實現。它們所使用的演算法統稱為DSA, Dynamic Storage Algorithms。


具體的演算法實現可以在下面的參考列表中找到對應的文檔, 也可以先看附16,會有一個總體的印象。


其中有一些基礎演算法也是相似,比如以二叉樹組織列表的演算法,也就是in-place, 笛卡爾樹 和red-block的差異。線上程上,則因為實現的不同,會導致記憶體佔用的差異。比如jemalloc在釋放時,並不需要在原來的分配線程執行釋放,只是被放回到分配線程的free list中去,ptmalloc則必須回到分配線程裡執行釋放,效能就相能弱一些。 tcmalloc則設計演算法,讓一個線程可以從它的鄰居那裡偷一些空間來(這個過程稱為transfer cache),這樣可以有效地利用線程間的記憶體。


優劣勢對比

ptmalloc 劣勢:多線程下的效能及記憶體佔用(線程間記憶體無法共用),並且記憶體用於儲存metadata開銷較大,在小記憶體配置上浪費比較多。優勢:算是標準實現,tcmalloc 劣勢:因為演算法的設計,佔用的記憶體較大。優勢:多線程下的效能。參考附6。jemalloc 優勢: 記憶體片段率低,多核下效能較tcmalloc更好。參考附17。


時間有限,沒有再深入研究。在實際應用中,還是有一些參數可以調整的,前提是要熟悉其實現,特別是效能評估的方法。



參考


這是我列的最長的參考清單了,前人的確已經做了很多的研究,我對其中內容只是泛讀,並不是所有內容都相關,只是覺得有些內容可以相互應證就也列進來了。
1. jemalloc關於使用red-block tree的反思 [連結]
  文章發佈於2008年,作者在2009年將其應用於FaceBook時,則是進行了演算法上最佳化。
2. 2011年jemalloc作者在FaceBook應用jemalloc後撰文介紹了jemalloc的核心演算法及在Facebook上應用效果。[連結] [早期的論文,有更多的細節]
3. Android片段化的度量 通過改造ROM做的實驗。
4. Hoard Offical [連結]
5. Mac OS上malloc是怎麼工作的[連結]
6. 關於WebKit應用tcmalloc的對比[連結]
7. How tcmalloc works[連結] [中文翻譯]
8. TCMalloc原始碼分析,很不錯資料。作者的網站還有其它乾貨值得一讀。[連結1]
9. dlmalloc早期的技術文檔,講述了其核心演算法。[連結]
10. ptmalloc源碼分析,講的很系統,非常值得一讀。[CSDN下載連結]
11. 介紹jemalloc的資料《更好的記憶體管理-jemalloc》[連結]
12. 替換系統malloc的四種方法 [連結]
13. 介紹針對即時系統進行最佳化的記憶體配置演算法TLSF,其中對動態分配演算法(DSA)做了些總結。[連結]
14. 維基百科上關於Thread Local Storage的說明, 也許你能感受到技術的相通性。[連結]
15. 針對即時系統進行各種分配演算法的對比,可以結合13一起看。[連結]
16. ptmalloc,tcmalloc和jemalloc記憶體配置策略研究。[連結]
17. Firefox3使用jemalloc後的總結,可以看到Firefox最佳化的思路。[連結] [Firefox使用的原始碼]
18. Chromimum Project: Out of memory handling, 裡面有不錯的觀點。 [連結]

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.