go-記憶體 Clerk

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

整合兩個文章,FixAlloc 和 MSpan。


記憶體模型如下:


FixAlloc

FixAlloc稱不上是核心組件,輔助實現整個記憶體 Clerk核心的一個基礎工具。引入FixAlloc的目的只是用來分配MCacheMSpan兩個特定的對象,所以記憶體 Clerk中有spanalloccachealloc兩個組件。MCache和MSpan兩個結構在malloc.h中有定義。

定義在malloc.h檔案中的FixAlloc結構如下,比較關鍵的三個欄位是alloc、list和chunk,其他的欄位主要都是用來統計一些狀態資料的,比如分配了多少記憶體之類。
struct FixAlloc{uintptr size;void *(*alloc)(uintptr);void (*first)(void *arg, byte *p);// called first time p is returnedvoid *arg;MLink *list;byte *chunk;uint32 nchunk;uintptr inuse;// in-use bytes nowuintptr sys;// bytes obtained from system};

FixAlloc的記憶體結構圖,一看就很簡單,簡單到沒有出現本文的必要了。

list指標上掛的一個鏈表,這個鏈表的每個節點是一個固定大小的記憶體塊,cachealloc中的list儲存的記憶體塊大小為sizeof(MCache),而spanalloc中的list儲存的記憶體塊大小為sizeof(MSpan)chunk指標始終掛載的是一個128k大的記憶體塊。

FixAlloc提供了三個API,分別是runtime·FixAlloc_Init、runtime·FixAlloc_Alloc和runtime·FixAlloc_Free。

分配一個mcache和mspan的虛擬碼:

MCache *mcache;mcache = (MCache *) runtime·FixAlloc_Alloc(cachealloc);MSpan *mspan;mspan = (MSpan *) runtime·FixAlloc_Alloc(spanalloc);

這段虛擬碼展示的是分配一個MCache和MSpan對象,記憶體 Clerk並不是直接使用malloc類函數向系統申請,而是走了FixAlloc。使用FixAlloc分配MCache和MSpan對象的時候,首先是尋找FixAlloc的list鏈表,如果list不為空白,就直接拿一個記憶體塊返回使用; 如果list為空白,就把焦點轉移到chunk上去,如果128k的chunk記憶體中有足夠的空間,就切割一塊記憶體出來返回使用,如果chunk記憶體沒有剩餘記憶體的話,就從作業系統再申請128k記憶體替代老的chunk。FixAlloc的固定對象分配邏輯就這麼簡單,相反釋放邏輯更簡單了,釋放的對象就是直接放到list中,並不會返回給作業系統。當然mcache的個數基本是穩定的,也就是底層線程個數,但span對象就不一定那麼穩定了,所以FixAlloc的記憶體可能增長的因素就是span的對象太多。


MSpan

MSpan和FixAlloc一樣,都是記憶體 Clerk的基礎工具組件,但和FixAlloc沒太大的交集,各自發揮功效而已。span(MSpan簡稱span)是用來管理一組組page對象,先解釋一下page,page就是一個4k大小的記憶體塊而已。span就是將這一個個連續的page給管理起來,注意是連續的page,不是東一個西一個的亂擺設的page。

MSpan結構定義在malloc.h標頭檔中,代碼如下:

struct MSpan{MSpan*next;// in a span linked listMSpan*prev;// in a span linked listPageIDstart;// starting page numberuintptrnpages;// number of pages in spanMLink*freelist;// list of free objectsuint32ref;// number of allocated objects in this spanint32sizeclass;// size classuintptrelemsize;// computed from sizeclass or from npagesuint32state;// MSpanInUse etcint64   unusedsince;// First time spotted by GC in MSpanFree stateuintptr npreleased;// number of pages released to the OSbyte*limit;// end of data in spanMTypestypes;// types of allocated objects in this span};

span結構比較重要的欄位,都出現在上面的結構圖中。span的結構中有pre/next兩個指標,是用來構造雙向鏈表的。span可能會用在分配小對象(小於等於32k)的過程中,也可能會用於分配大對象(大於32k),在分配不同類型對象的時候,span管理的中繼資料也大不相同。

npages表示是此span儲存的page的個數(比如:中就畫了3個page),start可以看作一個page指標,指向第一個page,有了第一個page當然就可以算出後面的任何一個page的起始地址了,因為span管理的始終是連續的一組page。這裡需要注意start的類型是PageID,由此可以看出這個start儲存的並不是第一個page的起始地址,而是第一個page的id值。這個id值是如何算出來的呢?其實給每個page算一個id,是非常簡單的事情,只要將這個page的的地址除以4096取整(虛擬碼:page_addr>>20)即可,當然前提是已經保證好了每個page按4k對齊。這樣一來每個page都有一個整數id了,並且任何一個記憶體位址都可以通過移位算出這個地址屬於哪個page。

start是span最重要的一個欄位,它維護好了所有的page。sizeclass如果是0的話,就代表這個span是用來分配大對象的,其他值是分配小對象。在分配小對象的時候,start欄位維護的所有page,最後將會被切分成一個一個的連續記憶體塊,記憶體塊大小是小對象的大小,這些切分出來的記憶體塊將被連結成為一個鏈表掛在freelist欄位上。分配大對象的時候,freelist就沒什麼用了。

span乾的活,也就這麼一點,反正就是管理一組連續的page。記憶體 Clerk中的每個page都會屬於一個span,page永遠不會獨立存在。span相關的API有:

// 初始化一個span結構,將分配的page放入到這個span中。voidruntime·MSpan_Init(MSpan *span, PageID start, uintptr npages);// 下面這些都是操作span構成的雙向鏈表了。voidruntime·MSpanList_Init(MSpan *list);boolruntime·MSpanList_IsEmpty(MSpan *list);voidruntime·MSpanList_Insert(MSpan *list, MSpan *span);voidruntime·MSpanList_Remove(MSpan *span);

Over ...

相關文章

聯繫我們

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