C++隨筆:.NET CoreCLR之GC探索(1)

  一直是.NET程序員,可是.NET的核心其實仍是C++,因此我準備花 一點時間來研究CoreCLR和CoreFX.但願這個系列的文章能給你們帶來 幫助。程序員

  GC的代碼有不少不少,並且結構層次對於一個初學者來講,很難很快或者很慢掌握,因此個人建議是,抓住一段功能,到實際當中去看。原本想從開頭 跟你們講的,可是看 開頭也是亂的,反正也沒有多少經驗,索性隨便講。函數

//返回第二個參數seg的直接前驅節點
heap_segment* heap_segment_prev (heap_segment* begin, heap_segment* seg)
{
	//判斷是否begin指針指向了NULL
    assert (begin != 0);

	//定義一個局部的變量,讓第一個參數begin指向這個局部的指針。
    heap_segment* prev = begin;

	//首先獲得以begin爲基準的下一個堆片斷的地址
    heap_segment* current = heap_segment_next (begin);

	//循環判斷「下一個」地址是否是和函數的第二個參數的地址是指向同一塊內存
    while (current && current != seg)
    {
		//把獲得的current當前的地址臨時指向prev
        prev = current;
		//去嘗試獲得下一個地址
        current = heap_segment_next (current);
    }

	//上一個循環結束,若是當前segment等於形參,返回上一個
    if (current == seg)
    {
        return prev;
    }
	//若是當前segment是頭結點,那麼沒有直接前驅,返回空
    else
    {
        return 0;
    }
}

  

注意這裏的heap_segment是類名,定義在gcpriv.h中,heap_segment_prev是方法的名稱。heap_segment,個人理解其實很簡單,就是 「堆的集合」,集合當中的每一個元素,就是它的一個segment,每一個元素是鏈式鏈接的。ui

讓咱們來看看這個類的真容吧,這很重要,要注意它們的類型不少 都是Uint8_t,那麼 這個結構體有什麼特色呢?按照posix標準,通常整形對應的*_t類型爲:this

       1字節     uint8_t
       2字節     uint16_t
       4字節     uint32_t
       8字節     uint64_tspa

由此咱們能夠獲得一個很重要的信息,它們存放的片斷都是 以一個字節爲原子的,爲何會用這種方式去存儲,這個我也不得而知。3d

class heap_segment
{
public:
    uint8_t*        allocated; //已經分配的空間
    uint8_t*        committed; //已經被提交的
    uint8_t*        reserved; //已經被存儲的
    uint8_t*        used; //已經被使用的
    uint8_t*        mem;  //空間
    size_t          flags; //標記
    PTR_heap_segment next; //下一個堆的片斷
    uint8_t*        plan_allocated; //「將要」 分配的空間
	//若是BACKGROUND_GC被定義的話,執行以下代碼(後臺GC)
#ifdef BACKGROUND_GC
    uint8_t*        background_allocated; //後臺分配
    uint8_t*        saved_bg_allocated; //已經保存的後臺分配
#endif //BACKGROUND_GC

	//多個堆(不止是一個堆)
#ifdef MULTIPLE_HEAPS
    gc_heap*        heap;   //這個類畢竟複雜,之後會專門抽出章節來講
#endif //MULTIPLE_HEAPS

#ifdef _MSC_VER
// Disable this warning - we intentionally want __declspec(align()) to insert padding for us
#pragma warning(disable:4324)  // structure was padded due to __declspec(align())
#endif
    aligned_plug_and_gap padandplug;
#ifdef _MSC_VER
#pragma warning(default:4324)  // structure was padded due to __declspec(align())
#endif
};

其中我來 解釋一下PTR_heap_segment,它實際上是一個自定義類型指針

typedef DPTR(class heap_segment)               PTR_heap_segment;

下面咱們再回到heap_segment_prev這個方法,若是你能看懂我下面畫的這幅圖,你就應該能理解這個方法到底要幹什麼了。其實意圖很明顯,咱們能夠把heap當作是一個鏈表,暫時咱們 不知道這個鏈表究竟是什麼鏈表,這個並不重要,重要的是,咱們首先必須知道咱們要從哪一個節點開始,而後要尋找哪個節點,就是分別對應下圖的第一個參數和第二個參數,首先咱們會進入一個while循環,若是咱們第一次獲得的不爲NULL並且獲得的heap的下一個節點(segment)不和第二個參數吻合,至於怎麼吻合?就是2個地址是否是指指向同一塊內存!直到找到爲止,返回這個heap指定位置的前置節點。blog

 

  heap_segment_next 這個函數,咱們看到,實際上是指向heap_segment的下一個heap,並做爲地址返回。內存

inline
PTR_heap_segment & heap_segment_next (heap_segment* inst)
{
  return inst->next;
}

  下面咱們再來 看一下heap_segment_in_range這個函數。咱們 先看看它的定義。it

inline
BOOL heap_segment_in_range_p (heap_segment* inst)
{
	//它返回一個bool類型,固然此BOOL是自定義的	
    return (!(inst->flags & heap_segment_flags_readonly) ||
            ((inst->flags & heap_segment_flags_inrange) != 0));
}

  固然咱們 必須知道一個基本的定義,下面變量是裏面自己定義好的。

#define heap_segment_flags_readonly     1
#define heap_segment_flags_inrange      2

  由此能夠推斷,heap_segment_in_range_p爲True.

下面咱們來看這個方法,註釋我已經打上了,可是我表示懷疑,爲何檢測邊界要經過這種一個一個鏈式的方式去檢測,這樣咱們 就要把整個鏈表跑一次,真的有點懷疑這是否是最好的方法。

//檢查堆的邊界,即最後一個元素
heap_segment* heap_segment_in_range (heap_segment* ns)
{
	//這裏是否會執行,決定於heap_segment的一些特性(我還不知道,因此不亂說)
    if ((ns == 0) || heap_segment_in_range_p (ns))
    {
        return ns;
    }
    else
    {
        do
        {
			//這段代碼實際上是一個循環,它的做用是檢測堆的一個「右邊」邊界
            ns = heap_segment_next (ns);
        } while ((ns != 0) && !heap_segment_in_range_p (ns));
        return ns;
    }
}

  今天還想寫的,不過很晚了,否則明天上班又起不來了。。。。先睡覺,晚安。  

相關文章
相關標籤/搜索