天天看點

垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

題記

内容來源

文章内容輸出來源:拉勾教育大前端高薪訓練營一期

目前階段的學習心得

我算是一個工作年限比較久的前端了,剛畢業時從事銷售工作,後來在2015年想要從事腳踏實地的工作,便選擇轉行網際網路。當時轉行時我和我同學選擇了不同的道路,她選擇參加ios教育訓練而我選擇自學。剛入行時因為沒有經驗,是以拿着月薪1.5K的薪水做着很繁雜的工作,前端、php、測試、産品、需求都ok。但沒有一個是我最擅長。忙碌的生活讓我逐漸意識到我或許走的不會很長久,我在2017年驚醒便放棄了天津的2K薪資來到了北京。北京公司是個小公司,倒是成長很快但技術方面沒有什麼提升。在2018年進入目前這家公司之後,因為機緣巧合的原因帶了小團隊,但我越發恐慌,我好想并不能帶給她們什麼,也不能帶領她們走向某一個方向,當我覺得自己’技’不配位的時候恰巧看到了拉勾的宣傳,莫名的緣分讓我成為了拉勾教育大前端高薪訓練營一期的學員。

成為學員之後,剛開始還蠻焦慮的。早已習慣懶散的生活和規律的生活因為加入了拉勾而變得異常充實和快樂,每次看視訊、聽直播、看群内分享的時候就可以感覺到原來自己太局限,我一個工作5年經驗的人竟然還在做初級工程師的工作。以上種種讓我很羨慕班裡那些工作一年的小夥伴,她們的前途一片光明。雖然我也是。

從加入大前端高薪訓練營到現在快3個月了,我對拉勾的課程品質絕對是非常滿意了。之前也在其他網站陸續買過一些課程,從我的認知中拉勾是最全面的、最細緻的一家。很多工作中我們不曾深入了解的工具、概念、實踐,老師都會在課程中帶領我們實踐一次,真乃實踐出真知呀。課程體系劃分合理、課程内容充實且全面、老師知識儲備超級豐富、講解夠細緻,我想一定是經過了很長時間的打磨才會有如此多的好評。

授課的主講老師是汪磊,我github唯一關注的粉絲(其實說明我太菜了),我這幾年的工作經曆也算見過一些大場面,但還是被汪老師的博學多識、幽默帥氣所吸引。之前還特意關注過汪老師的微網誌,發現汪老師一直從事網際網路教育教育訓練方向,想來他的經驗、學識、學習能力之是以如此優秀也是有原因的。持續深耕方可有今天的細緻與寬廣。

我們的班主任,一個細心且溫柔且負責任的美少女,其實很多時候我都要作業要不明天再寫吧(原諒我經常想偷懶),但老師常常會按時敲門來督促我們學習。我有想過,如果沒人監督沒人督促,我可能1個月都無法堅持。我的班主任總是晚上2點睡早晨6-7點起床,或許是我太不給力了。這些都是很細碎的點,但也正因為有她的陪伴、支援、鼓勵,我才發現我現在可以逐漸擺脫之前不好的習慣,如果每天不學習我甚至會覺得她能感覺到。現在真的變成了每天都要學習、每天都要記筆記的好習慣。

我們的助教老師熊熊老師和小北老師,常常在深夜或很早的時候就會回複我們的問題,每次的作業批改絕對是一絲不苟,我為什麼會有這樣的感觸?因為有一次我的作業漏寫了一道題老師還很認真的評價及解答_。

總體來說,對主講老師汪磊,心存敬意,因為尊敬也讓我更加認真的對待每一節視訊、每一次直播。對班主任,心存感恩,希望自己更自律可以讓她早點休息。對助教老師心存感激與敬佩,他們對待工作的态度也是我這個職場老人應該學習的。

最後,再來說一下故事開頭中我那位女同學的發展之路,在我持續3年拿月薪2K的時候,她早已月薪20K。其實我想說,成長有很多條路,真正走過(浪費)了這幾年之後我才發現我在最開始入行的時候應該選擇最快捷的那條路。不過現在的我已經在路上了,希望不會太晚。同時也希望各位小夥伴可以找到适合自己的學習方法。

什麼是垃圾、為什麼要回收

什麼是垃圾

在程式執行的過程中,隻要程式提出請求如定義變量、定義常量等,作業系統或運作時都會給我們配置設定記憶體空間。程式執行過程中會産生不再使用的變量、常量等,我們就稱為垃圾。

為什麼要回收

如果不進行垃圾回收,我們的記憶體被占用情況将會越來越嚴重,導緻後續的程式執行得不到足夠的記憶體空間,輕則影響系統性能,重則導緻程式崩潰。

如何回收

js、java、python、等都是采用程式搭載了GC(垃圾回收)算法進行自動回收。從申請記憶體空間、使用記憶體空間、釋放記憶體空間,GC算法會幫我們自動完成。

垃圾回收算法要做什麼事情

找到記憶體空間的垃圾

回收垃圾,讓程式可以再次利用這部分空間

垃圾回收算法相關概念

對象/頭/域

  • 對象:通過應用程式建立的資料的集合,資料存儲在記憶體空間裡。對象由頭Header和域field組成。
  • 頭:儲存對象本身資訊的部分稱之為頭Header,如對象的大小、對象的種類,對象使用者無法更改頭資訊
  • 域:對象使用者在可通路的部分稱之為域,個人了解就是對象的值。對象使用者可以更改域資訊。域中資料包含指針和非指針類,非指針就是值本身(可以了解為基礎資料類型)、指針指向記憶體中子產品區域也就是其他對象的位址。

指針

指針是指對象的域中存儲的是一個指向其他對象的位址

活動對象/非活動對象

活動對象/非活動對象:從根出發,可以通路的是活動對象,否則是非活動對象

配置設定

-配置設定:當程式建立對象時,向配置設定器申請,配置設定器尋找到合适的符合要求的空間并将空間位址傳回給程式

分塊

分塊:初始狀态下,堆被一個大的分塊所占據。

然後,程式會根據應用程式的要求把這個分塊分割成合适的大小,作為(活動)對象使用。活動對象不久後會轉化為垃圾被回收。此時,這部分被回收的記憶體空間再次成為分塊,為下次被利用做準備。也就是說,記憶體裡的各個區塊都重複着分塊→活動對象→垃圾(非活動對象)→分塊→ ……這樣的過程。

根:root,根是指向對象的指針的起點,浏覽器環境是window,node環境是global

垃圾回收時應用程式處于暫停狀态

堆與棧

- 記憶體 資料結構
new一個對象的引用或位址存儲在棧區,指向該對象存儲在堆區中的真實資料。由程式員配置設定和回收 是一棵完全二叉樹結構
存儲運作方法的形參、局部變量、傳回值。由系統自動配置設定和回收。 是一種連續存儲的資料結構,特點是存儲的資料先進後出

垃圾回收算法

标記-清除

  1. 标記清除Mark Sweep GC,1960年提出此概念,最早出現的GC算法。整個過程由标記+清除,兩個階段組成。
  • 标記階段:從根出發周遊所有能夠從根可達的對象,将其标記為活動對象
  • 清除階段:将未标記的非活動對象進行統一回收
  1. 什麼是可達對象?

    從根出發,如果是浏覽器就是從window出發,如果是node則是從global出發,可以通路到的就是可達對象。

  2. 周遊對象采用的什麼算法?怎麼實作周遊所有對象?

    周遊對象可以采用兩種算法,深度優先算法和廣度優先算法

  • 深度優先算法:Depth-First-Search,簡稱DFS。

    主要思路是從圖中一個未通路的頂點 V 開始,沿着一條路一直走到底,然後從這條路盡頭的節點回退到上一個節點,再從另一條路開始走到底…,不斷遞歸重複此過程,直到所有的頂點都周遊完成,它的特點是不撞南牆不回頭,先走完一條路,再換一條路繼續走。

    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收
    是以最終的執行順序是:1-2-5-9-3-6-10-7-4-8
               
  • 廣度優先算法:Breath First Search,簡稱BFS

    主要思路是指的是從圖的一個未周遊的節點出發,先周遊這個節點的相鄰節點,再依次周遊每個相鄰節點的相鄰節點。

    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

    動态效果可參考如下連結:https://s4.51cto.com/oss/202004/16/a2c7c61edcadffeed85c10f53f1c988c.gif。

    最終的執行順序是1-2-3-4-5-6-7-8-9-10。廣度優先算法采用隊列實作

  1. 缺點:
  • 效率問題:标記和清除環節因為需要找到所有可達對象,是以效率并不高
  • 空間碎片化:标記清除之後會産生大量不連續的記憶體碎片,空間碎片太多可能會導緻,碎片過多會導緻大對象無法配置設定到足夠的連續記憶體,進而不得不提前觸發GC,甚至導緻應用程式暫停

    [外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接

    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

引用計數

  1. 算法實作思路:通過在對象頭中配置設定一個空間來記錄該對象被引用的次數。如果該對象被其它對象引用,則它的引用計數加一,如果删除對該對象的引用,那麼它的引用計數就減一,當該對象的引用計數為0時,那麼該對象就會被立刻回收。
    let a = {name:'mm'}
    //1.先為{name:'mm'}開辟空間
    //2. 計數器開始工作,發現a引用了它,計數器+1
    //3. 當我們執行a=null時,計數就變為了0,立即觸發GC
               
  2. 優點:
  • 即可回收垃圾:每個對象都有自己的計數器,一旦計數器為0立刻進行垃圾回收
  • 最大暫停時間短:因為垃圾的即時回收,會大幅縮減程式的暫停時間
  • 沒必要沿指針查找:與标記清除算法不一樣,沒必要由根出發沿指針查找
  1. 缺點:
  • 計數器的增減比較繁重:
  • 計數器需要占用很多位:
  • 循環引用無法回收 a引用b,b引用a,這種情況始終無法回收

複制算法

  1. 算法實作思路:copying GC,把某個空間裡的活動對象複制到其他空間,把原空間裡的所有對象都回收掉。原空間稱為From空間,粘貼活動對象的新空間稱為To空間。當From空間完全被占滿時,GC會将活動對象全部複制到To空間,當複制完成後,該算法會把From空間和To空間互換,GC也就結束了。From和To空間大小必須一緻。
  2. 優點:
  • 不會發生碎片化:每次都是對其中的一塊進行記憶體回收,記憶體配置設定時也就不用考慮記憶體碎片等複雜情況
  • 優秀的吞吐量:隻搜尋從根出發的活動對象并隻複制活動對象
  1. 缺點:
  • 堆使用效率低下:GC複制算法把堆分為對等的兩份,通常隻能利用其中的一半來安排對象。也就是隻有一半堆被使用
  • 效率問題:在對象存活率較高時,複制操作次數多,效率降低;
    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

标記整理

  1. 算法實作思路

    分為标記和整理兩個階段:首先标記出所有需要回收的對象,然後讓所有存活的對象都向一端移動,然後直接清理掉端邊界以外的記憶體。不會立即進行垃圾回收

  2. 優點:不會産生空間碎片化
  3. 缺點:整理記憶體空間需要花費一定的時間
    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

分代回收

  1. 算法實作思路:

    分代回收的基本假設:絕大部分對象的生命周期都非常短暫,存活時間短。

    “分代收集”算法,把堆分為新生代和老年代,這樣就可以根據各個年代的特點采用最适當的收集算法。在新生代中,每次垃圾收集時都發現有大批對象死去,隻有少量存活,那就選用複制算法,隻需要付出少量存活對象的複制成本就可以完成收集。而老年代中因為對象存活率高、沒有額外空間對它進行配置設定擔保,就必須使用“标記-清理”或“标記-整理”算法來進行回收。

  2. 優點:因為針對不同的情況采用不同的GC算法,是以它的吞吐量得到了改善
  3. 缺點:在部分程式中會起到反作用,我們采用分代垃圾回收基于一個認知:很多對象年紀輕輕就稱為了垃圾,如果程式中對象都活的很久,會造成兩個問題(1)新生代GC花費的時間變多(2)老年代頻繁GC

認識V8的垃圾回收

認識V8

  • v8是一款主流的js執行引擎
  • v8采用即時編譯(速度很快)
  • v8記憶體設限:64位不超過1.5G,32位不超過800M

    為什麼會這樣設定?V8官方進行過一個測試:1.5G的垃圾,采用增量标記算法需要50毫秒,如果采用的是非增量回收需要1秒,1秒的停頓客戶已有感覺,如果垃圾大于1.5G會影響使用者體檢,故而将記憶體設定為1.5G

V8垃圾回收政策

  1. 采用分代回收的思想、将記憶體安裝一定的規則分為新生代記憶體區、老生代記憶體區,針對不同的記憶體區采用不同的垃圾回收機制
垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收
  1. v8常用的GC算法:
  • 分代回收
  • 空間複制
  • 标記清除
  • 标記整理
  • 标記增量(為了提高效率)
  1. V8如何回收新生代對象
    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收
  • 将記憶體分為大小相同的兩塊:新生代記憶體塊中存放新生代對象也就是存活時間較短的對象(比如局部變量),老生代記憶體中存放老生代對象也就是存貨時間教長的對象
  • 64位系統中新生代記憶體的大小為32M,32位系統中新生代記憶體大小為16M
  • 新生代對象采用的GC算法主要有複制算法+标記整理
  • 新生代緩存區:分為兩個大小相同的區域from和to.

from:使用狀态,在聲明變量時都會進入到from空間,當from使用達到一定的程度觸發GC,首先進行活動對象的标記,不可達對象不标記,然後進行整理,将不連續的記憶體空間整理為連續記憶體空間。然後将活動對象從from拷貝到to中,然後将from完全釋放。

to: 空閑狀态

垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收
  • 拷貝過程中存在晉升:晉升就是将新生代記憶體區中的對象轉移至老生代對象

    出現晉升的時機有:

    (1)一輪GC之後還存活的對象需要晉升

    (2)to空間的使用率超過25%将所有對象轉移至老生代空間,設定25%這個門檻值的原因是當這次回收完成後,這個To空間會變為From空間,接下來的記憶體配置設定将在這個空間中進行。如果占比過高,會影響後續的記憶體配置設定

  1. V8如何回收老生代對象

    64位系統中老生代記憶體的大小為1.4G,32位系統中新生代記憶體大小為700M

  • 老年代對象就是指存活時間比較長的對象如全局變量、閉包等。
  • 老年代對象主要采用标記清除、标記整理、增量标記算法,主要使用标記清除,但會産生空間碎片化問題,即使這樣,V8底層針對老年代對象也主要使用的是此種GC算法(效率高)。
  • 什麼時候用标記整理?當我們想要把新生代存儲區的内容挪到老生代存儲區中,但老生代存儲區的記憶體空間不能滿足,此時就會進行一輪标記整理對碎片化空間進行整理,以釋放更多的空間
  1. 标記增量如果進行垃圾回收?

    因為垃圾回收會導緻程式暫停。将一整段回收操作分為多個階段進行,以友善和程式互動進行。

    垃圾回收算法及V8引擎的回收思想題記什麼是垃圾、為什麼要回收垃圾回收算法要做什麼事情垃圾回收算法相關概念垃圾回收算法認識V8的垃圾回收

繼續閱讀