2018年12月13日 星期四

Pro .NET Memory Management

Pro .Net Memory Management - CH1

Basic Concepts

  • 第一章主要講最基本要知道的項目
  • 早期的電腦(機械式電腦)其實沒有記憶體管理
  • 重要名詞
    • Memory,記憶體,可以分為RAM (Random Access Memory)及Non-Uniform Access Memory。差在存取時間是位置相關還是不相關
    • Address,描述記憶體區域的位置
    • ALU (arithmetic and logic unit),邏輯計算中心
    • Control Unit,用來從記憶體中讀取程式碼
    • Register,讓ALU及Control Unit可以快速讀取的區塊。它的速度是最快的,因為離ALU及Control Unit最近。
    • Word,一種記憶體的單位,在描述一些特殊行為時,描述記憶體大小會用幾個Word來表示
  • Control Unit有使用額外的Register叫做instruction pointer (IP) or program counter (PC)。這可以標記程式的位置,用來跑迴圈之類的。
  • 最早的程式是用Binary Code寫的,後來才有偏文字型式的Code,這叫做 assembly code。但是這種文字的Code也是要先轉成Binary Code 才可以交給電腦跑。這種轉換的流程稱做 Compilation,做這件的工具叫做Compiler

The Static Allocation

早期的程式的記憶體宣告都是在Compile時就要決定好的,因此可能造成記憶體的浪費。同時,若改變輸入值的數量,也就代表要重新Complie。
目前的語言也有類似的功能,如static 變數的宣告。

  • The Register Machine 指的是使用暫存器來做運算的電腦。目前的電腦都是將記憶體的值先放到暫存器中,再從記憶體拿另一個值加減乘除到暫存器後,做完所有的運算(中間的結果會一直在暫存器中被更新)後,最後再從暫存器存回記憶體。雖然有電腦是設計成不用暫存器直接在記憶體中操作,但是現在並沒有人用。
  • Stack的觀念也被用在電腦執行程式中。電腦中有兩塊記憶體,一個是放程式內容,一個是放目前的變數。程式在執行時,程式內容有一個Flag 叫 PS (Program Count) 用來記錄程式目前執行到那。另一個放變數的有一個Flag叫SP (Stack Point)表示目前可用變數的範圍。當程式執行時,若呼叫函數Call函數,則PS就會增加,代表移動到另一個函數,同時SP也會增加,代表可用的變數已經改變。當從函數中出來,則SP就會減少,也就代表變數記憶體的Release

Stack Machine

  • 指的是完成用Stack來處理的電腦。
  • 一般說來它會有兩個Stack,一個是放資料,一個是放流程。在運做上,如果是要做一個乘法,它就從資料的Stack中Pop兩個值出來乗好後再Push回去。
    它的好處是
  1. 不用煩惱暫存的資料要放在那裡,因此容易實作
  2. 流程是放在另一個Stack中,因為沒有數值在裡面,所以可以被重用,若使用壓縮則在減少記憶體可以得到更好的效果。
    介紹 Stack Machine的原因是因為.Net的RunTime就是這樣做的。

Pointer

  • Pointer 可以分成是Stack Pointer 或是 Instruction Pointer(program counter)
  • Pointer 的大小就是一個Word,所以和電腦的是32bit 或 64bit 有關。因為它很小,所以可以發在Stack中或是Register中
  • Pointer 可以使用特定的pointer arithmetic,用來快速找到下(上)一個記憶體區塊

Heap

  • Heap是一個用來動態配置物件的記憶體區塊。
  • Heap提供的記憶體區塊是連續的,要做到這件事,就要動態在執行時再分配記憶體。
  • 配置記憶體的動作稱為allocation,而釋放記憶體的流程稱為deallocation
  • Allocation及Deallocation的結果會造成Memery不連續,這個不連的狀況就是Fragmentation

Manual Memory Management

手動管理記憶體的壞處

  1. 必須知道要配置的大小
  2. 物件型別所佔用的大小必須知道,否則資料會出錯且難以debug
  3. 要記得每個配置記憶體的位置,因為要釋放它時要用到

  4. 很多缺點在多執行緒下其實會更複雜

Mutator

  • Mutator 負責程式中有關記憶體的操作,也就是程式中有用到記憶體部分就透過Mutator
  • 一般說來會有方法 New,Write,Read
  • 在真實世界中,這些方法通常和Allocator及Collector一起協作

Allocator

  • Allocator 負責動態配置記憶體,所以包含allocate 和 deallocate

Collector

  • 將不要用的物件的記憶體釋放
  • 如果知道物件已經不用了,一種是透過Counter計算存活值;一種是透過接觸性,看此物件是否在現存的程式中可以被訪問。

Reference Counting

參考記數是一種用來管理物件是否還有在用的方法,它有以下的優缺點

  • 優點
    1. 可以明確知道記憶體何時釋放,釋放的時機就是在計數出來不用的時候
    2. 較少的記憶體負擔,因為一知道不用,就立刻釋放,不會排程等待。
  • 缺點
    1. 會增加每次處理記憶體負擔,因為要不斷記錄次數
    2. 多執行緒下,次數的統計要有正確的同步處理
    3. 循環參考是有問題的,要特別設計去解

Tracking Collector

透過巡覽物件來判斷物件是否還可接觸。此流程分成兩個部分,Mark和Collect。

  • Mark 是先將還在用的物件做標記 ,流程如下
    1. 先將所有物件標成沒再用
    2. 找一個物件開始巡覽
    3. 把這個物件標成有在用,從這個物件再往下找
    4. 最後沒有被標成有在用的,就是沒有用的物件
  • Collect 是將沒有標記到的物件做清除的動作
  • Mark可能要進行標示,所以需要中斷所有的流程。而且,有可能在標示完後,一但流程又重新啟動後,整個記憶體又長得和剛剛不一樣。但是,這是沒關係的,因為沒有用的物件,還是保持沒有用,所以剛剛所做的事情沒有白費。
  • Mark有一個限制就是要清楚根物件的所在
  • Conservative Garbage Collector,是一種透過程式得知物件是否還需要的作法。它透過掃描所有的記憶體,這包括了Register, Stack, Heap。它將每一個記憶體內的資料來和Allocator的Heap所管理的。它並不是一個好的做法,那是誰會使用它呢? 在一個框架剛開發時,真正的記憶體管理策略還沒有想好時,可以很快的做一個記憶體管理。尤其它不需要任何Compile或是底層的支援,直接就是程式的邏輯,所以在Runtime直接執行即可。
  • Conservative Garbage Collector 的優缺點
    • 優:不需要環境支援就可以實作
    • 缺:不準確
  • Precise Garbage Collector相對於Conservative 就是得到了Complie及Runtime的支援,所以可以精準的知道記憶體的位置

Collect Phase

在記憶體回收的流程中,有兩個主要的動作,Sweep 及 Compact

  • Sweep 將不用的物件標示成不使用可以讓後續使用。實務上,可能會將不再用的記憶體區塊記錄下來,進行Merge。需要用的時候,掃描可用的區域,再度提供。掃描的方式一般也有兩種,找到可用就使用或是搜尋所有找出一個最適合的。
  • Sweep 用到後面,會產生需多小的記憶體區塊,這使得程式若需要一塊大的記憶體時,會找不到一塊適合的提供
  • Compact 是另一個方法,用來將Sweep產生的微小區塊進行壓縮
  • Compact 的作法也有兩種,一種是將要整理的記憶體先找一個空的地方放好,整理好後再放回來。但這種作法會需要很大的記憶體空間;另外一種方法是直接移動每一個記憶體,把空的地方補齊。惟一的問題是這個記憶體的移動巨體上是要如何實作? .Net有使用一個聰明的資料結構來做此事。

沒有留言:

張貼留言