深入理解GO語言之記憶體配置

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

前言:開通專欄後的第一篇文章,接下來將會就GO語言的記憶體,GC,並發編程等,深入理解GO這門語言。

一,記憶體模型概述

首先明確幾個概念:
(1) cache:線程私人的,每次對象分配時候先從cache查詢,小對象如果能獲得空閑記憶體則不用加鎖了。來看看cache的結構(省略了跟gc等相關的欄位)

type mcache struct {    alloc [numSpanClasses]*mspan // 用於分配的span    spanclass   spanClass  // size class and noscan (uint8)}

閱讀源碼我們可以看到cache有一個0到n的數組,每個數組掛載著一個鏈表,鏈表的節點代表著一個記憶體單元,而且同一個鏈表的節點的記憶體塊都是相等的,不同鏈表記憶體大小不同(大小根據spanclass的值作為下標來對應sizeclass.go中的class_to_size數組)。接下來我們看看記憶體配置在這裡的邏輯,我們可以找到malloc.go中的mallocgc(源碼就不貼上來了),其實邏輯很簡單,源碼注釋也很清楚,主要是判斷對象是否是小對象和大對象(小對象裡面還分為tiny和small)。大對象的話直接去堆中分配,小對象根據sizeclass取出一個記憶體塊鏈表,然後取出該鏈表的可用節點。對於tiny對象的處理非常有趣,它不能為指標,因為多個tiny對象分配到一個object,無法應對垃圾掃描。

(2) Central:線程共用的,如果在cache中找不到空閑記憶體,那麼cache就會申請一批小對象記憶體到本機快取中,這個過程是需要加鎖的。(注意:Central裡面是一個個的page)結構如下(同樣只保留了跟記憶體相關代碼):

type mcentral struct {    spanclass spanClass    nonempty  mSpanList // 有空閑記憶體的span列表    empty     mSpanList // 無空閑記憶體的span列表}

我們可以通過看malloc.go的mallocgc的代碼,我們發現如果cache記憶體不足,那麼會調用到mcache.go的refill函數,再到mcentral.go的cacheSpan函數,然後根據sizeclass大小取出相應的central擷取到相應的記憶體塊。在這一層記憶體管理粒度為span。

(3) Heap:線程共用的,如果Central中沒有閒置記憶體page,那麼就會從Heap中申請記憶體,這個過程需要加鎖。看看結構定義(列出幾個重要的跟記憶體相關的)

type mheap struct {    free      [_MaxMHeapList]mSpanList // 頁數在127以內的空閑span鏈表數組    freelarge mTreap                   // 頁數大於127時,轉而使用treap    allspans []*mspan                  // 記錄申請過的span    spans []*mspan                     // 記錄arena地區頁號跟mspan的映射關係    bitmap        uintptr // Points to one byte past the end of the bitmap    bitmap_mapped uintptr    //還有幾個跟arena相關的參數就不列舉了    }

在這層中,申請記憶體的單位為page,從heap申請的page是連續的,通過span來管理,這塊的邏輯我們可以看mheap.go的alloc_m函數。如果Central向Heap申請記憶體,那麼接下來就會根據page的個數去取最合適的span。接下來盜一個圖,覺得畫的很詳細:

二,記憶體 Clerk-Msapn和FixAlloc

這兩個都是記憶體 Clerk的基礎工具組件,在看代碼時候我們經常能看到這兩個,接下來就分別解釋下。
(1) Mspan
這是用來管理page對象的,而且是連續的page,結構定義如下:

type mspan struct {    next *mspan     // next span in list, or nil if none    prev *mspan     // previous span in list, or nil if none    list *mSpanList // 1.9後計劃移除的欄位,不做學習    startAddr uintptr // 第一個span的地址    npages    uintptr // 該span儲存的page個數    }

上面給出了幾個重要的欄位,可以看出,span結構的next和prev指標是用來構造雙向鏈表的,其實span的用處也只是管理一組連續的page而已,還是比較簡單的
(2) FixAlloc
這是用來管理MCache和MSpan的兩個特定的對象,結構定義如下:
type fixalloc struct {    size   uintptr    first  func(arg, p unsafe.Pointer) // called first time p is returned    arg    unsafe.Pointer    list   *mlink    chunk  uintptr     nchunk uint32    inuse  uintptr // in-use bytes now    stat   *uint64    zero   bool // zero allocations}

list上是一個鏈表,每個節點是一個固定大小的記憶體塊(cachealloc中的大小為sizeof(MCache),spanalloc的大小為sizeof(MSpan))。接下來我們看到mfixalloc.go中的alloc函數,邏輯大致如下:使用fixalloc分配MCache和Mspan時候,那麼首先會判斷list是否為空白,不為空白則返回一個記憶體塊使用,如果為空白,則判斷chunk上有無足夠的記憶體可用,再進行處理

三,總結

寫了兩天,終於寫完了,還是寫的很粗糙,相信隨著後面的學習,能學習到更多,再回來修改。
老大說過,閱讀源碼後不能只停留在讀源碼的層面,要想想讀完之後自己的收穫,多思考如果是我,會怎麼設計。
首先是提高了自己閱讀代碼的能力吧,然後學習到了treap樹,還有就是作者在設計這些記憶體模型時候的考慮的精妙的思想,例如如何更加快速的計算sizeclass,如何避免False Sharing等問題。有些問題比如FalseSharing是一個很隱形問題,但是確是非常重要的。

聯繫我們

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