程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> CLR探索系列-GC中的Card table和Brick Table(垃圾回收系列)

CLR探索系列-GC中的Card table和Brick Table(垃圾回收系列)

編輯:關於.NET

在CLR的垃圾回收子系統中,Card Table和Brick Table是兩個比較有意思的表。

在GC的過程中,一個Heap在運行了一段時間以後,已經分配的空間就會越來越大。在進行了一次局部代或者是完全的垃圾回收以後,就會涉及到一個GC堆的類似碎片整理的概念。整理優化一次GC Heap。同時,這種機制保證了譬如一個IIS Server在長時間的運行過程中的穩定性並且優化了其內存管理。

這樣的好處是顯而易見的,但是采用這種解決方案帶來的問題也很容易想到:譬如一個存在於GC Heap裡面的"Small" Object被移動了,同時它也被其它的object引用。出現了這種情況,在進行GC的時候,就需要遍歷整個GC的各種table,root,heap以及保留塊來搜索對這個對象的引用,然後更新這個引用。

這是一個相當消耗CPU資源的動作,幸運的是,GC使用了Card table來減小這個動作帶來的系統資源消耗。Card Table縮小了在這個搜索遍歷的過程中需要遍歷的范圍。

Card table實際上是一塊連續的內存區域,做為一個index,這塊內存區域裡面的每一個bit,都代表了GC Heap中的一塊連續的區域,這些bits就組成了一個card table。

CLR的實現中,Card Table中的一個bit就代表了GC heap裡面的128byte的區域。同時,對Card Table的update的動作是以byte為單位的。這就造成了每一次對Card Table的Update,影響到的其實是128*8=1kb這麼大的一個區域。

在DotNet的中間層,但凡涉及到修改一個Object的Ref的CIL Opcodes, 不僅僅會執行份內的修改ref的事情,同時還會很小心的update這個Card Table。

基於這種設計,在GC的時候,就可以先查找Card Table來看看哪些Object的Ref被修改了,然後只是針對這些區域去進行搜索遍歷來Update GC Heap中其它的地方對這個對象的引用。

這些Bit位的Update,可以由WriteBarrierHelper和ErectWriteBarrier 這兩個方法來完成:

//update一個Card table的方法。void GCHeap::ErectWriteBarrier(OBJECTREF *dst, OBJECTREF ref)
{
  // 檢查dst的地址是不是在heap之內的地址。
  if (((*(BYTE**)&dst) < g_lowest_address) || ((*(BYTE**)&dst) >= g_highest_address))
    return;
if((BYTE*) OBJECTREFToObject(ref) >= g_ephemeral_low
&& (BYTE*) OBJECTREFToObject(ref) < g_ephemeral_high)
  {
    size_t card = gcard_of((BYTE*)dst);
    BYTE* pCardByte = ((BYTE*) g_card_table) + card / CARDS_PER_BYTE;
       //每一次update是以一個byte為單位的。
     BYTE bitMask = (BYTE) (1 << (card % 8));
    if( !((*pCardByte) & bitMask) )
    {  
           //如果這個有ref被修改,那麼這個card的一個byte裡面都被置為1
      *pCardByte = 0xFF;
    }
  }
}    

同時,在update一個bit的時候,還使用了一種叫做wirte barrier的技術。這種技術,在程序修改一個ref的內容的時候,可以被編譯器得知。這個技術在card update裡面,具體到某個平台上面是一段匯編的代碼,其實個人認為就是對CIL代碼的一個擴展。

Bricks和card差不多。它的最主要的作用,是Collector用來定位一個Object在Heap裡面的位置。它的表示形式,是一個16位有符號int類型的數組。每一個單元叫做brick slot,cover2048byte的內存區域。對於每一個Brick slot,每一個16bit的成員都可以有三種表現形式:

1.十六位的正數表示偏移。

2.一個負數表示相對於Brick table本身的唯一。

3.保留值,做為一個標志位來使用。

另外,這兩種結構,都不能保證完全表現一個Heap裡面的狀態信息。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved