Erlang 垃圾回收機制(一)

每兩周一篇的連續(xù)更新來啦,雖然主要是為了完成社區(qū)任務 ??

Erlang Process 內(nèi)存分布

在了解 GC 之前影钉,我們先來看看 Erlang 進程的內(nèi)存分布是怎樣的:

          Shared Heap                        Erlang Process Memory Layout                  
                                                                                             
 +----------------------------------+      +----------------------------------+              
 |                                  |      |                                  |              
 |                                  |      |  PID / Status / Registered Name  |       Process
 |                                  |      |                                  |       Control
 |                                  |      |   Initial Call / Current Call    +---->  Block  
 |                                  |      |                                  |       (PCB)  
 |                                  |      |         Mailbox Pointers         |              
 |                                  |      |                                  |              
 |                                  |      +----------------------------------+              
 |                                  |      |                                  |              
 |                                  |      |        Function Parameters       |              
 |                                  |      |                                  |       Process
 |                                  |      |         Return Addresses         +---->  Stack  
 |                                  |      |                                  |              
 |    +--------------+              |      |         Local Variables          |              
 |    |              |              |      |                                  |              
 |    | +------------+--+           |      +-------------------------------+--+              
 |    | |               |           |      |                               |  |              
 |    | | +-------------+--+        |      |  ^                            v  +---->  Free   
 |    | | |                |        |      |  |                               |       Space  
 |    | | | +--------------+-+      |      +--+-------------------------------+              
 |    +-+ | |                |      |      |                                  |              
 |      +-+ |  Refc Binary   |      |      |  Mailbox Messages (Linked List)  |              
 |        +-+                |      |      |                          ?       |              
 |          +------^---------+      |      |  Compound Terms (List, Tuples)   |       Process
 |                 |                |      |                                  +---->  Private
 |                 |                |      |     Terms Larger than a word     |       Heap   
 |                 |                |      |                                  |              
 |                 +--+ ProcBin +-------------+ Pointers to Large Binaries    |              
 |                                  |      |                                  |              
 +----------------------------------+      +----------------------------------+              
  • PCB: 進程控制塊保存一些有關進程的信息寸认,如進程標識符(PID)纵顾、當前狀態(tài)(正在運行、等待间唉,等等)绞灼、注冊名稱、初始時和當前正在調(diào)用的函數(shù)呈野,等等低矮。PCB 還保存了一些指向傳入本進程的消息的指針,這些消息以鏈表的形式存儲在堆中被冒。
  • Stack: 向下增長的內(nèi)存區(qū)域军掂,保存了函數(shù)入?yún)ⅰ⒑瘮?shù)調(diào)用返回地址昨悼、以及本地變量等等蝗锥。大一點的數(shù)據(jù)結(jié)構(gòu),比如 List 和 Tuple 這些是保存在 Heap 里的率触。
  • Heap: 向上增長的內(nèi)存區(qū)域终议, 保存了進程的消息郵箱、復合的數(shù)據(jù)類型比如 Lists, Tuples and Binaries 以及像浮點數(shù)這種超過一個機器字(word)長度的對象。注意超過 64 個字節(jié)長度的 Binary 不是存儲在這個進程的私有 Heap 里的穴张,這種情況下進程的私有 Heap 里面存的是指向另一個全局共享 Heap 里 Binary 對象的指針细燎。這個共享 Heap 是可以被所有的 Process 訪問的,保存在全局共享 Heap 里面的“大 Binary” 叫做 Refc Binary (Reference Counted Binary)皂甘,而存在私有 Heap 里面的指針叫做 ProcBin玻驻。

每個 Erlang 進程都有自己的棧和堆,這些棧和堆分配在同一個內(nèi)存塊中偿枕,并"相向而行"??璧瞬。當棧和堆相遇時(也就是說此進程的內(nèi)存用盡時),將觸發(fā)垃圾回收益老。如果沒能回收足夠的內(nèi)存彪蓬,進程將會去申請更多的內(nèi)存。

我們來看一下進程的 PCB 里面的內(nèi)容:

1> hipe_bifs:show_pcb(self()).
P: 0x00007f7f3cbc0400
---------------------------------------------------------------
Offset| Name | Value              | *Value |
    0 | id   | 0x000001d0000003a3 | |
   72 | htop | 0x00007f7f33f15298 | |
   96 | hend | 0x00007f7f33f16540 | |
   88 | heap | 0x00007f7f33f11470 | |
  104 | heap_sz | 0x0000000000000a1a | |
   80 | stop | 0x00007f7f33f16480 | |
  592 | gen_gcs | 0x0000000000000012 | |
  594 | max_gen_gcs | 0x000000000000ffff | |
  552 | high_water | 0x00007f7f33f11c50 | |
  560 | old_hend | 0x00007f7f33e90648 | |
  568 | old_htop | 0x00007f7f33e8f8e8 | |
  576 | old_head | 0x00007f7f33e8e770 | |
  112 | min_heap_size | 0x00000000000000e9 | |
  328 | rcount | 0x0000000000000000 | |
  336 | reds | 0x0000000000002270 | |
  16  | tracer | 0xfffffffffffffffb | |
  24  | trace_fla.. | 0x0000000000000000 | |
  344 | group_lea.. | 0x0000019800000333 | |
  352 | flags | 0x0000000000002000 | |
  360 | fvalue | 0xfffffffffffffffb | |
  368 | freason | 0x0000000000000000 | |
  320 | fcalls | 0x00000000000005a2 | |
  384 | next | 0x0000000000000000 | |
  48  | reg | 0x0000000000000000 | |
  56  | nlinks | 0x00007f7f3cbc0750 | |
  616 | mbuf | 0x0000000000000000 | |
  640 | mbuf_sz | 0x0000000000000000 | |
  464 | dictionary | 0x0000000000000000 | |
  472 | seq..clock | 0x0000000000000000 | |
  480 | seq..astcnt | 0x0000000000000000 | |
  488 | seq..token | 0xfffffffffffffffb | |
  496 | intial[0] | 0x000000000000320b | |
  504 | intial[1] | 0x0000000000000c8b | |
  512 | intial[2] | 0x0000000000000002 | |
  520 | current | 0x00007f7f3be87c20 | 0x000000000000ed8b |
  296 | cp | 0x00007f7f3d3a5100 | 0x0000000000440848 |
  304 | i | 0x00007f7f3be87c38 | 0x000000000044353a |
  312 | catches | 0x0000000000000001 | |
  224 | arity | 0x0000000000000000 | |
  232 | arg_reg | 0x00007f7f3cbc04f8 | 0x000000000000320b |
  240 | max_arg_reg | 0x0000000000000006 | |
  248 | def..reg[0] | 0x000000000000320b | |
  256 | def..reg[1] | 0x0000000000000c8b | |
  264 | def..reg[2] | 0x00007f7f33ec9589 | |
  272 | def..reg[3] | 0x0000000000000000 | |
  280 | def..reg[4] | 0x0000000000000000 | |
  288 | def..reg[5] | 0x00000000000007d0 | |
  136 | nsp | 0x0000000000000000 | |
  144 | nstack | 0x0000000000000000 | |
  152 | nstend | 0x0000000000000000 | |
  160 | ncallee | 0x0000000000000000 | |
  56  | ncsp | 0x0000000000000000 | |
  64  | narity | 0x0000000000000000 | |
---------------------------------------------------------------

我們使用 hipe_bifs:show_pcb 來打印 PCB 的內(nèi)容捺萌,請注意 OTP 23 似乎刪掉了這個工具档冬,所以盡量用 OTP 22 之前的版本。

其中 htopstop 是分別指向 Heap 和 Stack 頂部的指針桃纯,“頂部” 的意思是堆或者棧上的下一個可用的內(nèi)存片段酷誓。heaphend 指針分別指向整個 Heap 的起始和終止位置。然后 heap_size 字段是 Heap 的大小态坦,單位是字 (words)盐数。就是說,在 64 位機器上:hend - heap = heap_sz * 8 伞梯,32 位機器上:hend - heap = heap_sz * 4 玫氢。最后要說的就是 min_heap_size = 0xe9(words),這個指的是 Heap 的初始大小谜诫,同時也是當 Erlang 進程內(nèi)存收縮的時候所允許的 Heap 最小值漾峡,默認值是 0xe9(233)

需要注意的是喻旷,前面我們介紹的 Heap 和 Stack 兩個概念生逸,其實在 Erlang 進程的內(nèi)存里是同一塊內(nèi)存,heaphend 兩個指針分別指向了這塊內(nèi)存的開始和終止位置且预。這也是為什么上面 hipe_bifs:show_pcb/1 的結(jié)果里槽袄,對于堆棧只有個 stop 指針而沒有對應的 stacksend》嫘常基于這些我們再重新畫一下文章開始的內(nèi)存圖:

+--+-------------------------------+ <--- *hend              高地址
|                                  |              
|        Function Parameters       |              
|                                  |       Process
|         Return Addresses         +---->  Stack  
|                                  |              
|         Local Variables          |              
|                                  |              
+-------------------------------+--+ <--- *stop         
|                               |  |              
|  ^                            v  +---->  Free   
|  |                               |       Space  
+--+-------------------------------+              
|                                  |              
|  Mailbox Messages (Linked List)  |              
|                          ?       |              
|  Compound Terms (List, Tuples)   |       Process
|                                  +---->  Private
|     Terms Larger than a word     |       Heap   
|                                  |              
---+ Pointers to Large Binaries    |              
|                                  |              
+----------------------------------+ <--- *heap             低地址

現(xiàn)在我們可以簡單的介紹一下垃圾回收了遍尺。

簡單地將,Erlang 的垃圾回收是一個分代的垃圾回收怀估,并且是基于單進程的狮鸭,所以它不會 Stop the world合搅。從上面我們了解到的 Erlang 進程內(nèi)存結(jié)構(gòu)來說,它是工作在進程的私有 Heap 之上(從 *heap 到 *hend)歧蕉,然后額外還要去清掃 ProcBin 指向的全局共享 Heap 中的那些內(nèi)存灾部。

關于 Erlang 垃圾回收的進一步的細節(jié),我們將放到本系列的后續(xù)文章中講解惯退。

引用文獻以及資料:

  1. http://erlang.org/doc/apps/erts/GarbageCollection.html

  2. https://hamidreza-s.github.io/erlang%20garbage%20collection%20memory%20layout%20soft%20realtime/2015/08/24/erlang-garbage-collection-details-and-why-it-matters.html

  3. https://github.com/happi/theBeamBook

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赌髓,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子催跪,更是在濱河造成了極大的恐慌锁蠕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懊蒸,死亡現(xiàn)場離奇詭異荣倾,居然都是意外死亡,警方通過查閱死者的電腦和手機骑丸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門舌仍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人通危,你說我怎么就攤上這事铸豁。” “怎么了菊碟?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵节芥,是天一觀的道長。 經(jīng)常有香客問我逆害,道長头镊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任魄幕,我火速辦了婚禮拧晕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘梅垄。我一直安慰自己,他們只是感情好输玷,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布队丝。 她就那樣靜靜地躺著,像睡著了一般欲鹏。 火紅的嫁衣襯著肌膚如雪机久。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天赔嚎,我揣著相機與錄音膘盖,去河邊找鬼胧弛。 笑死,一個胖子當著我的面吹牛侠畔,可吹牛的內(nèi)容都是我干的结缚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼软棺,長吁一口氣:“原來是場噩夢啊……” “哼红竭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喘落,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤茵宪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘦棋,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體稀火,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年赌朋,在試婚紗的時候發(fā)現(xiàn)自己被綠了凰狞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡箕慧,死狀恐怖服球,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情颠焦,我是刑警寧澤斩熊,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站伐庭,受9級特大地震影響粉渠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜圾另,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一霸株、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧集乔,春花似錦去件、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汗唱,卻和暖如春宫莱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哩罪。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工授霸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巡验,地道東北人。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓碘耳,卻偏偏與公主長得像显设,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子藏畅,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容