go記憶體分配器

Iwanna發表於2020-10-18

閱讀 意隨行筆記draveness關於go的記憶體管理的部分總結

  1. 流程
    使用者程式(mutator)通過分配器(allocator)從堆(heap)中獲得新記憶體空間,通過收集器(collector)回收空間

  2. 分配器
    go採用空閒連結串列分配器,分配記憶體,並且採用隔離適應的方法

  3. 空閒連結串列分配器
    當使用者程式申請記憶體時,空閒連結串列分配器會依次遍歷空閒的記憶體塊,找到足夠大的記憶體,然後申請新的資源並修改連結串列

    意思是說,分配的記憶體空間必然是連續的,若這塊不夠,就看下一塊夠不夠,直到找到足夠大的一塊,而不能是多塊湊起來組合的(簡而言之就是要連續記憶體)

  4. 隔離適應
    將記憶體分割成多個連結串列,每個連結串列中的記憶體塊大小相同,申請記憶體時先找到滿足條件的連結串列,再從連結串列中選擇合適的記憶體塊

  5. 分級

    1. 執行緒快取(thread cache)
    2. 中心快取(central cache)
    3. 頁堆(page heap)
      執行緒快取只屬於當前執行緒,不需要加鎖所以不存在競爭
      32k以上的記憶體申請需要從頁堆裡分配
  6. 記憶體管理的基本單位(mspan)
    mspan實現了go記憶體管理的隔離適應效果
    每個mspan能分配出去的物件大小(sizeclasses)是固定的
    每個mspan裡都包含了指向上一個和下一個mspan的指標的欄位,且指向的是同一個mcache下的同sizeclasses的內容

  7. 執行緒快取(mcache)

    type mcache {
     ...
     alloc [numSpanClasses]*mspan //numSpanClasses = 67*2  = 134
     ...
    }

    mcache是繫結在GMP的P(排程器)上的
    alloc一開始為空的大小為134(67個指標型別的和67個非指標型別的)的陣列,使用過程中再去對應規格的中心快取(mcentral)動態申請mspan

  8. 中心快取(mcentral)

    type mcentral struct {
     lock      mutex
      spanclass spanClass   //spanClass Id
      nonempty  mSpanList // 所有未被使用的空閒span
      empty     mSpanList // 已經被mcache拿走,未歸還的會掛載到這裡
    
      nmalloc uint64 //這個mcentral分配mspan的累積計數
    }
    1. 中心快取是公共區域,多個mcache都可以去申請空間所以得加鎖
    2. 每個中心快取只管理一種大小(spanclass)的mspan(所以mcentral的總數不超過67 * 2 = 134)
    3. mcache來申請mspan時,先在nonempty裡面看有沒有能用的,沒有再去empty裡面找,都沒有就去頁堆裡面重新再申請一些空間
  9. 頁堆(mheap)
    每個mheap大小為64M
    最多有4M個mheap
    所以最多能用256TB
    每個指標佔8B
    所以元資訊的大小為4M*8B=32M(也就是要用32M的記憶體去記錄這256T的分配情況)


  1. 單個大物件的大小是否不能超過單個mheap大小(64M)
  2. 針對大物件歸屬的mspan,裡面管理的物件大小是不是可能不一樣???(參考第六點,是否正確?)
  3. mspan的個數是不是也只有134個?
  4. mspan裡面的元素可能來源於不同的mheap?
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章