常見垃圾回收方法

一、標記清除法(Mark And Sweep)java

第一步:從根部出發,遍歷全局,而後對全部可達的對象進行標記python

第二步:對全部未標記的對象進行清除c++

優勢:方法簡單,速度較快。缺點:容易產生較多的內存碎片。算法

採用這種方式的語言:lua等c#

二、標記整理回收(mark-compact)緩存

第一步和標記清除法同樣,標記全部可達對象安全

第二步將未標記的對象清除,同時將現有對象的空間合併多線程

優勢:沒有內存碎片。缺點:合併空間的時候,引用該對象的全部線程都會被掛起,合併完成後纔會從新執行。併發

採用這種方式的語言:c#等性能

三、標記複製回收(mark-copy)

複製算法開闢了兩個相等的空間,每次只使用其中的一塊空間

第一步標記

第二步將全部標記過的對象,複製到另外一塊空間,當複製完成後,指向原有對象的指針指向新的對象。所有複製完成後,釋放原有的空間。

優勢:沒有內存碎片,不會gc ,效率高   缺點:須要額外的內存空間

採用這種方式的語言:java的新生代

四、引用計數算法(reference counting)

對象每次被引用的時候對引用次數加1,每次被引用對象被刪除時,則對引用次數減1,當引用計數爲0時,則刪除對象。

優勢:迅速,每次當對象引用次數爲0時,則立刻就會被清除。無需系統支持,去肯定程序的根。

缺點:

  一、計數賦值器帶來額外的開銷。因此不適合通用的大容量的內存管理器。

  二、多線程的程序中,可能釋放過早。引用計數的存儲指針操做是原子化的,併發線程卻同時進行讀取和修改,開發者要避免更新指針槽過程當中出現的競爭問題。

  三、對單個對象的簡單操做也會引起內存請求(更新引用次數),會「污染」高速緩存

  四、沒法解決循環引用問題

  五、有可能卡頓,當刪除一個大的根節點的時候,須要去遞歸刪除每個子孫節點。

循環引用的解決方法:

  一、按期用標記算法做爲補充處理

  二、設爲強引用和弱引用,把可能產生環的引用設爲弱引用,全部強引用可達且不成環,當強引用次數爲0時,刪除對象(這種方法爲了一些安全性緣由,性能開銷大,只有少數語言使用)

    c++的智能指針的弱引用和這種算法的弱引用不同,c++的弱引用只能肯定是否可達,主要是爲了不非法訪問。

  三、部分跟蹤算法,循環引用指針出現有2個條件:

    (1)環狀指針內部,全部引用對象都有內部對象指針產生

    (2)若是刪除某一對象後,引用計數仍然爲0,則說明產生了環狀

    掃描對象,若是一個對象的全部引用都是循環引用,則進行處理。臨時移除對目標對象的引用次數,從而移除內部指針的引用次數,若是目標對象引用計數仍然大於0,則說明存在外部引用,不然一塊兒處理掉。

計數回收的語言有:python等

五、分代算法

將內存分爲幾個區域,不一樣狀態的對象放進不一樣的區域裏,對每一個區域採起不一樣的垃圾回收策略,能夠兼顧優勢,可是比較複雜。

採用分代回收的語言:java等

java將內存分紅了新生代、年老代和永久代

新生代:新生代用標記複製回收,由於絕大部分建立的對象都是臨時用的,很快會被回收掉,同時爲了提升性能,和適合用複製回收,複製回收的兩塊區域大小是9:1。

年老代:當在新生代裏複製必定次數尚未被回收之後,則放到年老代裏,年老代採用複製標記回收。

永生代:當在年老代理必定時間沒有被回收,則放入永生代,永生代採用複製整理回收。

分紅的好處針對不一樣性質的對象,採用不一樣的處理方式。複製整理回收的回收效果好,可是整理過程當中會形成gc,因此用了兩層過渡,減小複製整理的發生。

相關文章
相關標籤/搜索