Erlang併發機制 – 垃圾回收

Erlang中每一個進程都有獨立的堆內存,默認的大小是233個words(可配置),並以Fibonacci序列的順序增加(233對應fib(11))。不過,當堆內存增大到必定程序時,增加速度減緩,好比內存大於fib(35)=14M的時候,堆內存開始不以Fibonacci序列增加(具體參見[$R15B_OTP_SRC/erts/emulator/beam/erl_gc.c --> erts_init_gc]裏的說明)。通常狀況下,進程所用到的數據都放在各自的堆內存中。spa

 

         Erlang的GC機制跟其它語言(好比Java)相比,很重要的一點是,它的GC是以進程爲單位進行的(通常狀況下,GC搜索的根對象主要包括進程棧以及進程信箱中的對象)。Erlang系統中,GC進行時,會掛起整個系統(當前結點上的因此調度隊列),也就是說它的GC也是「stop the world」。可是,就算一個系統中有大量進程,總共佔用幾個G的內存,它的GC的延遲也會很低,這是由於每一個進程可能只使用很小的內存(好比20K),在這麼小的內存上進行GC所花費的時間很小,基本能夠忽略不計。orm

在Erlang中能夠經過spawn_opt來指定初始堆內存大小,若是這個數值足夠大(須要診斷後肯定),那麼就能夠徹底避免GC。進程在銷燬時,統一收回其所擁有的全部堆內存,而不須要進行GC,由於堆內存是每一個進程私有的。對象

 

         Erlang中,堆內存被分紅年輕代和年老代。進程在分配新數據時,會將數據放在年輕代中(分代的理論基礎是大部分剛建立的對象會在不久的未來再也不使用)。只查看年輕代對象的GC稱爲minor GC,查看全部堆內存對象的GC稱爲major GC,所以minor GC比major GC更頻繁,也更快。年輕代中的對象通過兩到三次minor GC後,纔會被拷貝到年老代。隊列

 

Minor GC進程

         年青代堆內存中存在一個標記位:高水位線(high water mark),比這個標記位地址小的對象稱爲較老的年輕代(older young generation),大於這個地址的稱爲較年輕的年輕代(younger young generation)。內存

         Minor GC時,會分配一塊新的堆內存,用於存放在能夠在本次GC後能夠生存下來的較年輕的年輕代。年輕代內存中被進程的根對象所引用的對象,若是它的地址小於高水位線,則會被拷貝到年老代堆內存,不然將其拷貝到新分配的堆內存中。而後根據新分配堆內存以及較老的年輕代堆內存中對象的引用,將全部活着的對象按原來的位置關係拷貝到新分配的堆內存或者年老代中。ci

         Minor GC進行時,年老代堆內存不會被掃描,以加快GC速度。Minor GC完成後,會根據GC過程當中是否有較老的年輕代對象來決定高水位線的位置:若是存在,高水位線設置成it

新的年輕代堆內存的開始地址;若是不存在,則會設置成年輕代堆內存的堆頂地址。io

 

 

Major GC基礎

         Major GC時,年輕代堆內存和年老代堆內存中被根對象間接或直接引用到的對象都會被拷貝到新的堆內存中,高水位線會被設置成新的堆內存的堆頂地址。新的堆內存成爲當前進程的年輕代堆,原來的老的堆內存(年輕代以及年老代)都會被釋放。

相關文章
相關標籤/搜索