天天看點

記憶體管理:虛拟位址空間和堆

作者:後端開發進階
記憶體管理:虛拟位址空間和堆

準備用一個系列來總結一下記憶體管理涉及到的相關知識,範圍從底層的資料結構和算法,到上層的API的使用,這裡的記憶體管理,目前打算主要是側重在堆的管理,本文作為一個引子,先粗略講一下虛拟位址空間、堆管理、arena,接下來會陸續講一下堆管理算法、malloc實作、new/delete等C++内容的相關實作等,但也希望如果以後有時間的話,也可以把棧和甚至和cache相關的内容也加到這個系列裡,現在大概是這麼規劃的,不知道能寫幾篇,先努力寫着看吧。

一、虛拟位址空間

說記憶體管理,就必須要先說虛拟位址空間,這是現代程式運作的根本,基本概念大家都知道就不在這裡贅述了,盡量把這部分的精華部分盡量簡單的總結出來,先看一下程序虛拟位址空間的總體布局,以32位Linux系統為例:

記憶體管理:虛拟位址空間和堆

基于上圖的虛拟位址空間布局來簡單說下ELF檔案是怎樣映射到程序虛拟位址空間的,ELF檔案被組織成如下圖左列出的一系列section,其中具有相同屬性(R/W/E)的section再組成一個segment,以segment為機關映射到程序的虛拟位址空間,其中虛拟位址空間中的segment要做到頁大小對齊,下圖也一同簡要展示了虛拟位址空間到實體位址空間的映射,通過MMU完成,具體的細節請大家網上或者書上查資料,這都是比較基本的概念,這裡就不贅述了:

記憶體管理:虛拟位址空間和堆

其它系統原理類似,都是将可執行程式組織成若幹segment連同用到的動态庫和kernel映射到程序的虛拟位址空間,主要差别在于不同segment映射的起始位址、大小不同等,比如32位Linux系統的Text segment起址是0x08048000,64位Linux系統的Text segment起址是0x00400000,再比如相對32位Linux系統的kernel space是1G,32位Windows的kernel space是2G等等,後面相關内容全部以32位Linux系統為例說明。

二、堆

從圖1中可以看到堆所處的位置,它位于Data segment的上面,這部分堆空間是程式預設建立的,主要是給程式的主線程用的,在特定的情況下(比如malloc申請大記憶體的時候、多線程的時候等),堆的内容還會擴充到圖1中的Memory mapping segment區域,假如一共存在三個堆區域,它們的分布如下圖所示:

記憶體管理:虛拟位址空間和堆

應用申請堆空間,主要是通過三個系統函數完成的:brk、sbrk、mmap,在前面圖3中,主線程的堆空間是用brk或者sbrk申請的,heap1和heap2這兩個Memory mapping segment是用mmap申請的。其中brk和sbrk使用的是同一個系統調用,根本原理是改變上面圖3中的brk ptr這個指針的位置,mmap的功能很強大,在申請堆空間的時候主要使用它的Anonymous mapping的功能,下面是一個從上到下的簡略調用關系:

記憶體管理:虛拟位址空間和堆

在堆中,記憶體被管理的基本機關是塊,glibc中的名字叫chunk,為了不引起歧義,這個系列以後全部用chunk這個詞來表示堆中的記憶體塊,如下圖所示(其中的free chunk會用後續文章介紹的某種算法維護,這裡沒有畫出):

記憶體管理:虛拟位址空間和堆

三、arena

很多人可能沒聽說過這個概念,這是Linux堆管理中常用的一個術語,這個詞的意思是競技場,感覺這個詞用的非常傳神,堆這塊地方可不就是一個競技場麼。下面從glibc實作的角度簡單說下arena,在glibc中,arena的個數是有限制的,限制條件如下:

system arena number
32bit 2 x cpu_core_number + 1
64bit 8 x cpu_core_number + 1

每個線程一定對應一個arena,但是一個arena可以給多個線程使用,同時一個arena可以由一個或者多個圖3中的堆區組成,它們之間的關系如下圖:

記憶體管理:虛拟位址空間和堆

在glibc中,每一個heap的開始有一個heap_info的描述頭(注意main thread所用到的那個arena對應的heap沒有這個描述頭,也就是緊挨着data segment的那個使用brk/sbrk來動态擴充的heap),定義如下:

// malloc/arena.c
typedef struct _heap_info {
  // Arena for this heap
  struct malloc_state *ar_ptr;
  // Previous heap
  struct _heap_info *prev;
  // Current size in bytes
  size_t size;
  // Size in bytes that has been mprotected PROT_READ|PROT_WRITE
  size_t mprotect_size;
  // padding
  char pad[];
} heap_info;           

從上面代碼可以看出,如果一個arena用到多個heap,那麼這些heap通過prev這個指針連接配接起來,并且通過ar_ptr這個指針指向所屬的arena,arena在glibc中對應的資料結構是malloc_state,定義如下:

// malloc/malloc.c
struct malloc_state {
  // Flags (formerly in max_fast)
  int flags;
  // Set if the fastbin chunks contain recently 
  // inserted free blocks, Note this is a bool 
  // but not all targets support atomics on booleans
  int have_fastchunks;
  // Fastbins
  mfastbinptr fastbinsY[NFASTBINS];
  // Base of the topmost chunk -- not otherwise kept in a bin
  mchunkptr top;
  // The remainder from the most recent split of a small request
  mchunkptr last_remainder;
  // Normal bins packed as described above
  mchunkptr bins[NBINS * 2 - 2];
  // Bitmap of bins
  unsigned int binmap[BINMAPSIZE];
  // Linked list
  struct malloc_state *next;
  // Linked list for free arenas.  
  struct malloc_state *next_free;

  // Number of threads attached to this arena
  INTERNAL_SIZE_T attached_threads;
  // Memory allocated from the system in this arena
  INTERNAL_SIZE_T system_mem;
  INTERNAL_SIZE_T max_system_mem;
};           

這裡隻簡單列一下和arena相關的兩個資料結構,其中具體的字段含義等以後将malloc實作的時候再細說,這裡先貼出來大家好有個基本概念。

四、reference

這個系列主要參考的資料有下面這些,後續的文章沒有特殊情況的話就不再提及了,大家有興趣的話也可以直接去翻看下面所述的章節:

  • 深入了解計算機系統:虛拟存儲器這一章
  • 程式員的自我修養:可執行檔案的裝載與程序這一章
  • Effective C++:定制new和delete這一章
  • Modern Effective C++:Smart Pointers這一章
  • C++并發程式設計實戰:C++記憶體模型和原子類型操作這一章
  • GCC的官方文檔
  • cppreference的記憶體管理相關函數的manual
  • 網上的一些博文: https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/ https://sploitfun.wordpress.com/2015/02/11/syscalls-used-by-malloc https://fantiq.github.io/2019/05/13/malloc%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%8Earena%E7%9A%84%E5%88%9B%E5%BB%BA/ https://introspelliam.github.io/archives/ Safe-Linking - Eliminating a 20 year-old malloc() exploit primitive - Check Point Research tcache 源碼分析及利用思路

原文連結:https://zhuanlan.zhihu.com/p/374431199 原文作者:月踏

繼續閱讀