當前位置:首頁 » 操作系統 » 垃圾回收演算法手冊

垃圾回收演算法手冊

發布時間: 2022-09-28 11:12:58

『壹』 老鳥對於剛入行的程序猿有什麼忠告

我認為首先在IT這行應該是很公平的也很公正的,它是靠著技術來吃飯的,就算你用在厚的關系你要沒技術在這,那肯定是不是的,當然老闆出外哦。所以入這行不管你以前的背景多麼的光鮮亮麗或拿不出手,只要能夠去學習,和謙卑的狀態去請教。


  • 知識要牢固

我認為不管在那一行,畢竟你是新人首先就是姿態放低,心態放平,即使同事水平沒你高,也別說出來。寫你自己的代碼就好。操作伺服器要謹慎+謹慎,尤其是線上執行sql的時候。熱愛編程,周末有時間就寫些自己感興趣的大小項目。

  • 總結

學習這倆字應該是最好的,不管是扎實的基礎知識,和人事的處理關系等等的一些方面吧,總之是一定要抱著學習的態度的。

『貳』 《垃圾回收的演算法與實現》pdf下載在線閱讀,求百度網盤雲資源

《垃圾回收的演算法與實現》(中村成洋)電子書網盤下載免費在線閱讀

資源鏈接:

鏈接: https://pan..com/s/1F0QUPK8Y3isGgD28oxt9Gw

提取碼: 8qkr

書名:垃圾回收的演算法與實現

作者:中村成洋

譯者:丁靈

豆瓣評分:8.2

出版社:人民郵電出版社

出版年份:2016-7-1

頁數:456

內容簡介:

★ Ruby之父Matz作推薦語:上古傳承的魔法,徹底揭開垃圾回收的秘密!

★ 日本天才程序員兼Lisp黑客竹內郁雄審校

本書前半介紹基本GC演算法,包括標記-清除GC、引用計數、復制演算法的GC、串列GC的演算法、並發GC的演算法等。後半介紹V8、Rubinius、Dalvik、CPython等幾種具體GC的實現。本書適合各領域程序員閱讀。

『叄』 jvm垃圾回收演算法有哪些

1.標記–清除演算法

執行步驟:

  • 標記:遍歷內存區域,對需要回收的對象打上標記。

  • 清除:再次遍歷內存,對已經標記過的內存進行回收。

2.復制演算法

將內存劃分為等大的兩塊,每次只使用其中的一塊。當一塊用完了,觸發GC時,將該塊中存活的對象復制到另一塊區域,然後一次性清理掉這塊沒有用的內存。下次觸發GC時將那塊中存活的的又復制到這塊,然後抹掉那塊,循環往復。

3. 標記–整理演算法

因為前面的復制演算法當對象的存活率比較高時,這樣一直復制過來,復制過去,沒啥意義,且浪費時間。所以針對老年代提出了「標記整理」演算法。

執行步驟:

  • 標記:對需要回收的進行標記

  • 整理:讓存活的對象,向內存的一端移動,然後直接清理掉沒有用的內存。

4. 分代收集演算法

當前大多商用虛擬機都採用這種分代收集演算法,這個演算法並沒有新的內容,只是根據對象的存活的時間的長短,將內存分為了新生代和老年代,這樣就可以針對不同的區域,採取對應的演算法。如:

  • 新生代,每次都有大量對象死亡,有老年代作為內存擔保,採取復制演算法。

  • 老年代,對象存活時間長,採用標記整理,或者標記清理演算法都可。

『肆』 JVM有哪些垃圾回收演算法

標記-清除,標記-復制,標記-整理

『伍』 各種編程語言的實現都採用了哪些垃圾回收演算法

java語言:
. 採用Reference Counting的垃圾回收器
對於採用Reference Counting的垃圾回收器,系統為堆上每一個對象都維護一個計數器,當一個對象被創建並且別引用時,這個計數就被置為1。當有新的變數引用該對象,計數器進行自加運算。當一個引用超出作用范圍或者被賦予新值的時候,計數器進行自減運算。引用計數為0的對象,會被作為垃圾回收。當一個對象被回收,該對象所引用的對象的引用計數都會相應減少,因而,一個對象的回收有時會引起其它對象的回收。
Reference Counting方式的垃圾回收器,好處在於可以在很短的時間內運行,不會長時間的中斷普通的程序運行,因而在RealTime的系統中應用較為普遍。 Reference Counting方式的垃圾回收器,問題在於無法識別循環引用,比如父類對象還有子類引用的情況,即便父類和子類都已經不再能被訪問到(unreachable),引用計數也把它們清除。另外一個問題是引用計數器的加減運算會增加系統的計算開銷。 2. 採用Tracing的垃圾回收器
採用Tracing的垃圾回收器,遍歷由根節點(root nodes)出發的引用關系圖。在遍歷過程中遇到的對象,就被標記為活動。標記既可以是對應對象中的某一個標志,也可以是獨立的點陣圖中的標志。當遍歷完成以後,那些沒有被標記的對象,就被作為垃圾回收了。最基本Tracing演算法是"Mark and Sweep" 垃圾回收器的另外一個責任是清除堆上的碎片(Fragmentation)。對於Mark and Sweep的垃圾回收器通常有兩種實現方法來減少堆上的碎片: 壓縮(Compacting)和拷貝(Copying)

在編程語言Python中,使用也是引用計數演算法。

節點拷貝演算法
節點拷貝演算法是把整個堆分成兩個半區(From,To), GC的過程其實就是把存活對象從一個半區From拷貝到另外一個半區To的過程,而在下一次回收時,兩個半區再互換角色。在移動結束後,再更新對象的指針引用。

『陸』 5、垃圾回收機制

JVM的垃圾回收機制主要涉及三個方面的問題:
1.JVM有哪些垃圾回收演算法?各自有什麼優勢?
2.CMS垃圾回收器是如何工作的?有哪些階段?
3.服務卡頓的元兇到底是什麼?
Java不用程序來管理內存的回收,但這些內存是如何回收的?
其實,JVM有專門的線程在做這件事情。當內容空間達到一定條件時,會自動觸發,這個過程就叫GC,負責GC的組件被稱為垃圾回收器。JVM規范沒有規定垃圾回收器怎麼實現,它只需要保證不要把正在使用的對象回收掉就可以。在現在的伺服器環境中,經常被使用的垃圾回收器有CMS和G1,但JVM還有其它幾個常見的垃圾回收器。
GC的過程是先找到活躍的對象,然後把其他不活躍的對象判定為垃圾,然後刪除,所以GC只與活躍的對象有關,和堆的大小無關。
接下來學習下分代垃圾回收的內存劃分和GC過程,再有就是常見的垃圾回收器。
這篇比較重要,因為幾乎所有的垃圾回收器都是在這些基本思想上演化出來的。

GC的第一步就是找出活躍的對象,根據GC Roots遍歷所有的可達對象,這個過程就叫作標記。

如上圖所示,圓圈代表對象,綠色的代表GC Roots,紅色的代表可以追溯到的對象,標記後,有多個灰色的圓圈,代表都是可被回收的對象。

清除階段就是把未被標記的對象回收掉。
這種方式有一個明顯的問題,會產生碎片空間。
比如申請了1k、2k、3k、4k、5k的內存

由於某些原因,2k和4k的內存不再使用,交給垃圾回收器回收。

解決碎片問題,就需要進行內存整理。
有一個思路就是提送一個對等的內存空間,將存活的對象復制過去,然後清除員內存空間。
在程序設計時,一般遇到擴縮容或者碎片整理問題時,復制演算法都是非常有效的。比如:HashMap的擴容使用的是同樣的思路,Redis的rehash也是如此。
整個過程如下圖

這種方式看似完美,解決了碎片問題,但是弊端也非常明顯,它浪費了一半的內存空間來做這個事情,如果原本資源就有限,這就是一種無法容忍的浪費。

不用分配一個對等的空間也是可以完成內存的整理工作。
可以把內存想像成一個非常大的數組,根據隨機的index刪除了一些數據,那麼對數組的清理不需要另外一個數組來進行支持的,使用程序就可以。
主要思路是移動所有的存活對象,且按照內存地址順序依次排列,然後將末端內存地址以後的內存全部收回。

對象的引用關系一般是非常復雜的,從效率上來說,一般整理演算法是要低於復制演算法的。
JVM的垃圾回收器,都是對以上幾種樸素演算法的結合使用,簡單看一下它們的特點:

效率一般,缺點是回造成內存碎片的問題。

復制演算法是所有演算法裡面效率最高的,缺點是造成一定的空間浪費。

效率比前兩者要差,但沒有空間浪費,也消除了內存碎片問題。

所以沒有最優的演算法,只有最合適的演算法。

JVM是計算節點,而不是存儲節點。最理想的情況就是對象使用完成之後,它的生命周期立馬就結束了,而那些被頻繁訪問的資源,我們希望它能夠常駐在內存里。
對象大致可以分為兩類:
1.大部分對象的生命周期都很短
2.其他對象則很可能會存活很長時間

現在的垃圾回收器都會在物理上或者邏輯上,把這兩類對象進行分區。我們把死的快的對象所佔的區域叫年輕代(Young Generation)。把其他活的長的對象所佔的區域叫作老年代(Old Generation),老年代在有時候會叫作Tenured Generation。

年輕代使用的垃圾回收演算法是復制演算法,因為年輕代發生GC後,會有非常少的對象存活,復制這部分對象是非常高效的
年輕代的內部分區

如圖所示,年輕代分為:一個伊甸園空間(Eden),兩個倖存者空間(Survivor)。
當年輕代中的Eden區分配滿的時候,就會觸發年輕代的GC(Minor GC),具體過程如下
1.在Eden區執行了第一次GC之後,存活的對象會被移動到其中一個Suvivor分區(from);
2.Eden區再次GC,這是會採用復制演算法,將Eden和from區一起清理,存活的對象會被復制到to區;接下來只需要清空from區就可以了
在整個過程中總會有一個Survivor分區是空置的。Eden、from、to的默認比例是8:1:1,所以只會造成10%的空間浪費。
這個比例是由參數-XX:SurvivorRatio進行配置的(默認為8)。
補充下不常提到的TLAB。TLAB全稱是Thread Local Allocation Buffer,JVM默認給每個線程開辟一個buffer區域,用來加速對象分配。這個buffer就放在Eden區中。
這個道理和Java語言中的ThreadLocal類似,避免了對公共區的操作,以及一些鎖競爭。

老年代一般使用"標記-清除"、"標記-整理"演算法。因為老年代的對象存活率一般是比較高的,空間又比較大,拷貝起來並不劃算,不如採取就地收集的方式。
對象進入老年代的途徑分類

如果對象夠老,會通過"提升"進入老年代。關於對象老不老,是通過它的年齡來判斷的。每發生一次Minor GC,存活下來的對象年齡都會加1,直到達到一定的閥值,就會提升到老年代,
這些對象如果變的不可達,直到老年代發生GC的時候才會被清理掉。
這個閥值可以通過參數 -XX:+MaxTenuringThreshold進行配置,最大值是15,因為它是用4bit存儲的(所以把這個值調的很大的文章,是沒有什麼根據的)。

每次存活的對象,都會放入其中一個倖存區,這個區域默認比例是10%,但無法保證每次存活的對象都小於10%,當Survivor空間不夠,就需要依賴其它內存(老年代)進行分配擔保。這個時候,對象也會直接在老年代上分配。

超出某個大小的對象直接在老年代分配,通過參數設置-XX:PretenureSizeThreshold進行配置的,默認為0,默認全部在Eden區進行分配。

有的垃圾回收演算法,並不要求age必須達到15才能晉升到老年代,它會使用一些動態的計算方法。比如,如果倖存區中相同年齡對象大小的和,大於倖存區的一半,大於或者等於age的對象將會直接進入老年代。
這些動態判定一半不受外部控制

對象的引用關系時一個巨大的網狀,有的對象在Eden區,有的可能在老年代,那麼這種跨代的引用是如何處理的呢?由於Minor GC是單獨發生的,如果一個老年代的對象引用了它,如何確保能夠讓年輕代的對象存活呢?
對於是、否的判斷,我們通常都會用到Bitmap(點陣圖)和布隆過濾器來加快搜索的速度,需要另外再學習下(如果不知道這兩個概念的話)
JVM也是用了類似的方法。其實,老年代是被分成眾多的卡頁(Card Page)的(一般數量是2的次冪)
卡表(Card Table)就是用於標記卡頁狀態的一個集合,每個卡表對應一個卡頁。
如果年輕代有對象分配,而且老年代有對象指向這個新對象,那麼這個老年代對象所對應內存的卡頁就會被標識為dirty,卡表只需要非常小的存儲空間就可以保留這些狀態,垃圾回收時,就可以先讀這個卡表,進行快速的判斷。

接下來學習HotSpot的幾個垃圾回收器,每種回收器都有各自的特點。在平常的GC優化時,一定要清楚現在用的是那種垃圾回收器。
下圖包含了年輕代和老年代的劃分,方便接下來的學習參考

處理GC的只有一條線程,並且在垃圾回收的過程中暫停一切用戶線程。
這是最簡單的垃圾回收器,雖然簡單,但十分高效,通常用在客戶端應用上。因為客戶端應用不會頻繁創建很多對象,用戶也不會感覺出明顯的卡頓。相反,它使用的資源更少,也更輕量級。

ParNew是Serial的多線程版本,由多條GC線程並行地進行垃圾清理。清理過程依然要停止用戶線程。追求低停頓時間,與Serial唯一區別就是使用了多線程進行垃圾回收,在多CPU環境下性能比Serial會有一定程度的提升;但線程切換需要額外的開銷,因此在單CPU環境中表現不如Serial。

另一個多線程版本的垃圾回收器。但與ParNew是有區別的
1.Parallel Scavenge:追求CPU吞吐量,能夠在較短時間內完成指定任務,適合沒有交互的後台計算,弱交互強計算。
2.ParNew:追求降低用戶停頓時間,適合互動式應用,強交互弱計算。

與年輕代的Serial垃圾回收器對應,都是單線程版本,同樣適合客戶端使用。
年輕代Serial,使用復制演算法。
老年代的Old Serial,使用標記-整理演算法。

Parallel Old回收器是Parallel Scavenge 的老年代版本,追求CPU吞吐量。

CMS(Concurrent Mark Sweep)回收器是以獲取最短GC停頓時間為目標的收集器,它在垃圾回收時使得用戶線程和GC線程能夠並發執行,因此在垃圾回收過程中用戶也不會感到明顯的卡頓。
長期看來,CMS垃圾回收器,是要被G1等垃圾回收器替換掉的,在Java8之後,使用它將會拋出一個警告!

除了上面幾個垃圾回收器,我們還有G1、ZGC等更加高級的垃圾回收器,它們都有專門的配置參數來使其生效。
通過-XX:PrintCommandLineFlags參數,可以查看當前Java版本默認使用的垃圾回收器。在Java13中,默認的回收器就是G1。
以下是一些配置參數:
1.-XX:+UseSerialGC 年輕代和年老代回收器
2.-XX:+UseParNewGC 年輕代使用ParNew,老年代使用Serial Old。
3.-XX:+UseParallelOldGC 年輕代和老年代哦都市用並行回收器。
4.-XX:+UseConcMarkSweepGC 表示年輕代使用ParNew,老年代使用CMS。
5.-XX:+UseG1GC 使用G1垃圾回收器
6.-XX:+UseZGC 使用ZGC垃圾回收器

這些垃圾回收器的關系還是比較復雜的,請看下圖

目前Java8還是主流使用版本,從Java8升級到高版本的Java體系是有一定成本的,所以CMS垃圾回收器還會持續一段時間

拋個問題,如果在垃圾回收的時候,又有新的對象進入怎麼辦?
為了保住程序不亂套,最好的辦法就是暫停用戶的一切線程,也就是在這段時間,是不能new對象的,只能等待,表象是在JVM上就是短暫的卡頓,什麼都幹不了,這個現象叫作Stop The World。
標記階段,大多數是要STW的。如果不暫停用戶進程,在標記對象的時候,有可能有其它用戶線程會產生一些新的對象和引用,造成混亂。
現在的垃圾回收器,都會盡量去減少這個過程。但即使最先進的ZGC回收器,也會有短暫的STW過程。我們要做的就是在現有基礎設施上,盡量減少GC停頓。
舉例說明下
某個高並發服務的峰值流量是10萬次/秒,後面有10台負載均衡的機器,那麼每台機器平均下來需要1w/s。假如某台機器在這段時間內發生了STW,持續了一秒,那麼至少需要10ms就可以返回的1萬個請求,需要至少等待1秒。

在用戶那裡的表現就是系統發生了卡頓。如果我們的GC非常的頻繁。這種卡頓就會特別的明顯,嚴重影響用戶體驗。
雖然說Java為我們提供了非常棒的自動內存管理機制,但也不能濫用,因為它是有STW硬傷的。

介紹了堆的具體分區,年輕代和老年代。介紹了多個常用的垃圾回收器,不同的垃圾回收器有不同的特點。各種垃圾回收器都是為了解決頭疼的STW問題,讓GC時間更短,停頓更短,吞吐量更大。
接觸了很多名詞,總結如下

1.Mark
2.Sweep
3.Copy
4.Compact

1.Young generation
2.Survivor
3.Eden
4.Old Generation |Tenured Generation
5.GC
--1.Minor GC
--2.Major GC

1.weak generational hypothesis
2.分配擔保
3.提升
4.卡片標記
5.STW

『柒』 《垃圾回收的演算法與實現》pdf下載在線閱讀全文,求百度網盤雲資源

《垃圾回收的演算法與實現》網路網盤pdf最新全集下載:
鏈接: https://pan..com/s/1bFL1ICR6xlb3au_B5sBhcQ

?pwd=afpy 提取碼: afpy
簡介: 本書分為「演算法篇」和「實現篇」兩大部分。演算法篇介紹了標記-清除演算法、引用計數法、復制演算法、標記-壓縮演算法、保守式GC、分代垃圾回收、增量式垃圾回收、RCImmix演算法等幾種重要的演算法;實現篇介紹了垃圾回收在Python、DalvikVM、Rubinius、V8等幾種語言處理程序中的具體實現。

『捌』 java垃圾是怎麼回收的,回收演算法

Java ,C#語言與C/C++語言一個很大的區別是java與C#具有自動垃圾回收機制。C++程序員經常需要絞盡腦汁的分析哪裡出現了內存泄漏。而在java,C#中,雖然有時也會出現內存泄漏,但大部分情況下程序員不需要考慮對象或者數據何時需要被銷毀。因此程序員不會因為錯誤的釋放內存而導致程序崩潰。垃圾回收的缺點是加大了程序的負擔,有可能影響程序的性能。
1.垃圾收集器的主要功能有
(1) 定期發現那些對象不再被引用,並把這些對象占據的堆空間釋放出來。
(2) 類似於操作系統的內存管理,垃圾收集器還需要處理由於對象動態生成與銷毀產生的堆碎塊,以便更有效的利用虛擬機內存。
2.區分活動對象與垃圾的演算法
(1)引用計數法
堆中每一個對象都有一個引用計數。當新創建一個對象,或者有變數被賦值為這個對象的引用,則這個對象的引用計數加1;當一個對象的引用超過生存期或者被設置一個新的值時,這個對象的引用計數減1。當對象的引用計數變為0時,就可以被當作垃圾收集。
這種方法的好處是垃圾收集較快,適用於實時環境。缺點是這種方法無法監測出循環引用。例如對象A引用對象B,對象B也引用對象A,則這兩個對象可能無法被垃圾收集器收集。因此這種方法是垃圾收集的早期策略,現在很少使用。
(2)跟蹤法
這種方法把每個對象看作圖中一個節點,對象之間的引用關系為圖中各節點的鄰接關系。垃圾收集器從一個或數個根結點遍歷對象圖,如果有些對象節點永遠無法到達,則這個對象可以被當作垃圾回收。
容易發現,這種方法可以檢測出循環引用,避免了引用計數法的缺點,較為常用。
3.常用垃圾回收機制
(1)標記-清除收集器
這種收集器首先遍歷對象圖並標記可到達的對象,然後掃描堆棧以尋找未標記對象並釋放它們的內存。這種收集器一般使用單線程工作並停止其他操作。
(2)標記-壓縮收集器
有時也叫標記-清除-壓縮收集器,與標記-清除收集器有相同的標記階段。在第二階段,則把標記對象復制到堆棧的新域中以便壓縮堆棧。這種收集器也停止其他操作。
(3)復制收集器
這種收集器將堆棧分為兩個域,常稱為半空間。每次僅使用一半的空間,虛擬機生成的新對象則放在另一半空間中。垃圾回收器運行時,它把可到達對象復制到另一半空間,沒有被復制的的對象都是不可達對象,可以被回收。這種方法適用於短生存期的對象,持續復制長生存期的對象由於多次拷貝,導致效率降低。缺點是只有一半的虛擬機空間得到使用。
(4)增量收集器
增量收集器把堆棧分為多個域,每次僅從一個域收集垃圾。這會造成較小的應用程序中斷。
(5)分代收集器
這種收集器把堆棧分為兩個或多個域,用以存放不同壽命的對象。虛擬機生成的新對象一般放在其中的某個域中。過一段時間,繼續存在的對象將獲得使用期並轉入更長壽命的域中。分代收集器對不同的域使用不同的演算法以優化性能。這樣可以減少復制對象的時間。
(6)並發收集器
並發收集器與應用程序同時運行。這些收集器在某點上(比如壓縮時)一般都不得不停止其他操作以完成特定的任務,但是因為其他應用程序可進行其他的後台操作,所以中斷其他處理的實際時間大大降低。
(7)並行收集器
並行收集器使用某種傳統的演算法並使用多線程並行的執行它們的工作。在多CPU機器上使用多線程技術可以顯著的提高java應用程序的可擴展性。
(8)自適應收集器
根據程序運行狀況以及堆的使用狀況,自動選一種合適的垃圾回收演算法。這樣可以不局限與一種垃圾回收演算法。
4. 火車演算法
垃圾收集演算法一個很大的缺點就是難以控制垃圾回收所佔用的CPU時間,以及何時需要進行垃圾回收。火車演算法是分代收集器所用的演算法,目的是在成熟對象空間中提供限定時間的漸進收集。目前應用於SUN公司的Hotspot虛擬機上。
在火車演算法中,內存被分為塊,多個塊組成一個集合。為了形象化,一節車廂代表一個塊,一列火車代表一個集合,見圖一
注意每個車廂大小相等,但每個火車包含的車廂數不一定相等。垃圾收集以車廂為單位,收集順序依次為1.1,1.2,1.3,1.4,2.1,2.2,2.3,3.1,3.2,3.3。這個順序也是塊被創建的先後順序。
垃圾收集器先從塊1.1開始掃描直到1.4,如果火車1四個塊中的所有對象沒有被火車2和火車3的對象引用,而只有火車1內部的對象相互引用,則整個火車1都是垃圾,可以被回收。
如圖二,車廂1.1中有對象A和對象B,1.3中有對象C,1.4中有對象D,車廂2.2中有對象E,車廂3.3中有對象F。在火車1中,對象C引用對象A,對象B引用對象D,可見,火車2和火車3沒有引用火車1的對象,則整個火車1都是垃圾。
如果火車1中有對象被其它火車引用,見圖三,掃描車廂1.1時發現對象A被火車2中的E引用,則將對象A從車廂1.1轉移到車廂2.2,然後掃描A引用的對象D,把D也轉移到車廂2.2,然後掃描D,看D是否引用其它對象,如果引用了其它對象則也要轉移,依次類推。掃描完火車1的所有對象後,剩下的沒有轉移的對象都是垃圾,可以把整個火車1都作為垃圾回收。注意如果在轉移時,如果車廂2.2空間滿了,則要在火車2末尾開辟新的車廂2.4,將新轉移的對象都放到2.4,即火車的尾部)
補充說明:垃圾回收器一次只掃描一個車廂。圖三中的對象B與C並不是立即被回收,而是先會被轉移到火車1的尾部車廂。即掃描完1.1後,B被轉移到火車1尾部,掃描完1.3後,C被轉移到車尾。等垃圾收集器掃描到火車1尾部時,如果仍然沒有外部對象引用它們,則B和C會被收集。
火車演算法最大的好處是它可以保證大的循環結構可以被完全收集,因為成為垃圾的循環結構中的對象,無論多大,都會被移入同一列火車,最終一起被收集。還有一個好處是這種演算法在大多數情況下可以保證一次垃圾收集所耗時間在一定限度之內,因為一次垃圾回收只收集一個車廂,而車廂的大小是有限度的。

『玖』 java有哪些垃圾回收演算法

常用的垃圾回收演算法有:
(1).引用計數演算法:
給對象中添加一個引用計數器,每當有一個地方引用它時,計數器值就加1;當引用失效時,計數器值就減1;任何時刻計數器都為0的對象就是不再被使用的,垃圾收集器將回收該對象使用的內存。
引用計數演算法實現簡單,效率很高,微軟的COM技術、ActionScript、Python等都使用了引用計數演算法進行內存管理,但是引用計數演算法對於對象之間相互循環引用問題難以解決,因此java並沒有使用引用計數演算法。
(2).根搜索演算法:
通過一系列的名為「GC Root」的對象作為起點,從這些節點向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當一個對象到GC Root沒有任何引用鏈相連時,則該對象不可達,該對象是不可使用的,垃圾收集器將回收其所佔的內存。
主流的商用程序語言C#、java和Lisp都使用根搜素演算法進行內存管理。
在java語言中,可作為GC Root的對象包括以下幾種對象:
a. java虛擬機棧(棧幀中的本地變數表)中的引用的對象。
b.方法區中的類靜態屬性引用的對象。
c.方法區中的常量引用的對象。
d.本地方法棧中JNI本地方法的引用對象。
java方法區在Sun HotSpot虛擬機中被稱為永久代,很多人認為該部分的內存是不用回收的,java虛擬機規范也沒有對該部分內存的垃圾收集做規定,但是方法區中的廢棄常量和無用的類還是需要回收以保證永久代不會發生內存溢出。
判斷廢棄常量的方法:如果常量池中的某個常量沒有被任何引用所引用,則該常量是廢棄常量。
判斷無用的類:
(1).該類的所有實例都已經被回收,即java堆中不存在該類的實例對象。
(2).載入該類的類載入器已經被回收。
(3).該類所對應的java.lang.Class對象沒有任何地方被引用,無法在任何地方通過反射機制訪問該類的方法。
Java中常用的垃圾收集演算法:
(1).標記-清除演算法:
最基礎的垃圾收集演算法,演算法分為「標記」和「清除」兩個階段:首先標記出所有需要回收的對象,在標記完成之後統一回收掉所有被標記的對象。
標記-清除演算法的缺點有兩個:首先,效率問題,標記和清除效率都不高。其次,標記清除之後會產生大量的不連續的內存碎片,空間碎片太多會導致當程序需要為較大對象分配內存時無法找到足夠的連續內存而不得不提前觸發另一次垃圾收集動作。
(2).復制演算法:
將可用內存按容量分成大小相等的兩塊,每次只使用其中一塊,當這塊內存使用完了,就將還存活的對象復制到另一塊內存上去,然後把使用過的內存空間一次清理掉。這樣使得每次都是對其中一塊內存進行回收,內存分配時不用考慮內存碎片等復雜情況,只需要移動堆頂指針,按順序分配內存即可,實現簡單,運行高效。
復制演算法的缺點顯而易見,可使用的內存降為原來一半。
(3).標記-整理演算法:
標記-整理演算法在標記-清除演算法基礎上做了改進,標記階段是相同的標記出所有需要回收的對象,在標記完成之後不是直接對可回收對象進行清理,而是讓所有存活的對象都向一端移動,在移動過程中清理掉可回收的對象,這個過程叫做整理。
標記-整理演算法相比標記-清除演算法的優點是內存被整理以後不會產生大量不連續內存碎片問題。
復制演算法在對象存活率高的情況下就要執行較多的復制操作,效率將會變低,而在對象存活率高的情況下使用標記-整理演算法效率會大大提高。
(4).分代收集演算法:
根據內存中對象的存活周期不同,將內存劃分為幾塊,java的虛擬機中一般把內存劃分為新生代和年老代,當新創建對象時一般在新生代中分配內存空間,當新生代垃圾收集器回收幾次之後仍然存活的對象會被移動到年老代內存中,當大對象在新生代中無法找到足夠的連續內存時也直接在年老代中創建。

熱點內容
入門c語言設計 發布:2025-05-17 12:08:31 瀏覽:40
c3演算法 發布:2025-05-17 12:04:19 瀏覽:364
phprecv 發布:2025-05-17 11:55:00 瀏覽:610
福建時鍾監控網關伺服器雲主機 發布:2025-05-17 11:54:28 瀏覽:248
c資料庫壓縮 發布:2025-05-17 11:39:22 瀏覽:960
安卓手機如何連接音響功放 發布:2025-05-17 11:37:48 瀏覽:958
破解exe加密視頻 發布:2025-05-17 11:23:41 瀏覽:976
我的世界伺服器圈太大了怎麼辦 發布:2025-05-17 11:15:21 瀏覽:614
便宜的免費雲伺服器 發布:2025-05-17 11:08:50 瀏覽:779
中國頂級dhcp解析伺服器地址 發布:2025-05-17 11:06:27 瀏覽:36