導航:首頁 > 編程語言 > java垃圾回收演算法

java垃圾回收演算法

發布時間:2024-03-26 17:29:07

Ⅰ JVM垃圾回收的「三色標記演算法」實現,內容太干

三色標記法是一種垃圾回收法,它可以讓JVM不發生或僅短時間發生STW(Stop The World),從而達到清除JVM內存垃圾的目的。JVM中的 CMS、G1垃圾回收器 所使用垃圾回收演算法即為三色標記法。

三色標記法將對象的顏色分為了黑、灰、白,三種顏色。

白色 :該對象沒有被標記過。(對象垃圾)

灰色 :該對象已經被標記過了,但該對象下的屬性沒有全被標記完。(GC需要從此對象中去尋找垃圾)

黑色 :該對象已經被標記過了,且該對象下的屬性也全部都被標記過了。(程序所需要的對象)

從我們main方法的根對象(JVM中稱為GC Root)開始沿著他們的對象向下查找,用黑灰白的規則,標記出所有跟GC Root相連接的對象,掃描一遍結束後,一般需要進行一次短暫的STW(Stop The World),再次進行掃描,此時因為黑色對象的屬性都也已經被標記過了,所以只需找出灰色對象並順著繼續往下標記(且因為大部分的標記工作已經在第一次並發的時候發生了,所以灰色對象數量會很少,標記時間也會短很多), 此時程序繼續執行,GC線程掃描所有的內存,找出掃描之後依舊被標記為白色的對象(垃圾),清除。

具體流程:

在JVM虛擬機中有兩種常見垃圾回收器使用了該演算法:CMS(Concurrent Mark Sweep)、G1(Garbage First) ,為了解決三色標記法對對象漏標問題各自有各自的法:

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標的收集器。目前很大一部分的java應用集中在互聯網網站或者基於瀏覽器的B/S系統的服務端上,這類應用通常都會較為關注服務的響應速度,希望系統停頓時間盡可能短,以給用戶帶來良好的交互體驗。CMS收集器就非常符合這類應用的需求(但是實際由於某些問題,很少有使用CMS作為主要垃圾回收器的)。

從名字(包含「Mark Sweep」)上就可以看出CMS收集器是基於標記-清除演算法實現的,它的運作過程相對於前面幾種收集器來說要更復雜一些,整個過程分為四個步驟,包括:1)初始標記(CMS initial mark) 2)並發標記(CMS concurrent mark) 3)重新標記(CMS remark) 4)並發清除(CMS concurrent sweep)

其中初始標記、重新標記這兩個步驟仍然需要「Stop The World」。初始標記僅僅只是標記一下GCRoots能直接關聯到的對象,速度很快;

並發標記階段就是從GC Roots的直接關聯對象開始遍歷整個對象圖的過程,這個過程耗時較長但是不需要停頓用戶線程,可以與垃圾收集線程一起並發運行;

重新標記階段則是為了修正並發標記期間,因用戶程序繼續運作而導致標記產生變動的那一部分對象的標記記錄,這個階段的停頓時間通常會比初始標記階段稍長一些,但也遠比並發標記階段的時間短;

最後是並發清除階段,清理刪除掉標記階段判斷的已經死亡的對象,由於不需要移動存活對象,所以這個階段也是可以與用戶線程同時並發的。由於在整個過程中耗時最長的並發標記和並發清除階段中,垃圾收集器線程都可以與用戶線程一起工作,所以從總體上來說,CMS收集器的內存回收過程是與用戶線程一起並發執行的。

在應對漏標問題時,CMS使用了增量更新(Increment Update)方法來做:

在一個未被標記的對象(白色對象)被重新引用後, 引用它的對象若為黑色則要變成灰色,在下次二次標記時讓GC線程繼續標記它的屬性對象

但是就算是這樣,其仍然是存在漏標的問題:

G1(Garbage First)物理內存不再分代,而是由一塊一塊的Region組成,但是邏輯分代仍然存在。G1不再堅持固定大小以及固定數量的分代區域劃分,而是把連續的Java堆劃分為多個大小相等的獨立區域(Region),每一個Region都可以根據需要,扮演新生代的Eden空間、Survivor空間,或者老年代空間。收集器能夠對扮演不同角色的Region採用不同的策略去處理,這樣無論是新創建的對象還是已經存活了一段時間、熬過多次收集的舊對象都能獲取很好的收集效果。

Region中還有一類特殊的Humongous區域,專門用來存儲大對象。G1認為只要大小超過了一個Region容量一半的對象即可判定為大對象。每個Region的大小可以通過參數-XX:G1HeapRegionSize設定,取值范圍為1MB~32MB,且應為2的N次冪。而對於那些超過了整個Region容量的超級大對象,將會被存放在N個連續的Humongous Region之中,G1的大多數行為都把Humongous Region作為老年代的一部分來進行看待,如圖所示

Card Table(多種垃圾回收器均具備)

RSet(Remembered Set)

是輔助GC過程的一種結構,典型的空間換時間工具,和Card Table有些類似。

後面說到的CSet(Collection Set)也是輔助GC的,它記錄了GC要收集的Region集合,集合里的Region可以是任意年代的。

在GC的時候,對於old->young和old->old的跨代對象引用,只要掃描對應的CSet中的RSet即可。邏輯上說每個Region都有一個RSet,RSet記錄了其他Region中的對象引用本Region中對象的關系,屬於points-into結構(誰引用了我的對象)。

而Card Table則是一種points-out(我引用了誰的對象)的結構,每個Card 覆蓋一定范圍的Heap(一般為512Bytes)。G1的RSet是在Card Table的基礎上實現的:每個Region會記錄下別的Region有指向自己的指針,並標記這些指針分別在哪些Card的范圍內。這個RSet其實是一個Hash Table,Key是別的Region的起始地址,Value是一個集合,裡面的元素是Card Table的Index。每個Region中都有一個RSet,記錄其他Region到本Region的引用信息;使得垃圾回收器不需要掃描整個堆找到誰引用當前分區中的對象,只需要掃描RSet即可。

CSet(Collection Set)

一組可被回收的分區Region的集合, 是多個對象的集合內存區域。

新生代與老年代的比例

5% - 60%,一般不使用手工指定,因為這是G1預測停頓時間的基準,這地方簡要說明一下,G1可以指定一個預期的停頓時間,然後G1會根據你設定的時間來動態調整年輕代的比例,例如時間長,就將年輕代比例調小,讓YGC盡早行。

SATB(Snapshot At The Beginning), 在應對漏標問題時,G1使用了SATB方法來做,具體流程:

因為SATB在重新標記環節只需要去重新掃描那些被推到堆棧中的引用,並配合Rset來判斷當前對象是否被引用來進行回收;

並且在最後G1並不會選擇回收所有垃圾對象,而是根據Region的垃圾多少來判斷與預估回收價值(指回收的垃圾與回收的STW時間的一個預估值),將一個或者多個Region放到CSet中,最後將這些Region中的存活對象壓縮並復制到新的Region中,清空原來的Region。

會,當內存滿了的時候就會進行Full GC;且JDK10之前的Full GC,為單線程的,所以使用G1需要避免Full GC的產生。

解決方案:

Ⅱ JVM垃圾收集機制

JVM垃圾回收機制是java程序員必須要了解的知識,對於程序調優具有很大的幫助(同時也是大廠面試必問題)。

要了解垃圾回收機制,主要從三個方面:

(1)垃圾回收面向的對象是誰?

(2)垃圾回收演算法有哪些?

(3)垃圾收集器有哪些?每個收集器有什麼特點。

接下來一一講解清楚:

一、垃圾回收面向的對象

也就是字面意思, 垃圾 回收嘛,重要的是垃圾,那什麼對象是垃圾呢,簡單來說就是無用的或已死的對象。這樣又引申出來什麼對象是已死的,怎麼判斷對象是否已死?

判斷對象是否已死有兩種演算法和對象引用分類:

(1)引用計數演算法:

也是字面意思,通過給對象添加引用計數器,添加引用+1,反之-1。當引用為0的時候,此時對象就可判斷為無用的。

優點:實現簡單,效率高。

缺點:無法解決循環引用(就是A引用B,B也引用A的情況)的問題。

(2)根搜索演算法(也就是GC Roots):

通過一系列稱為GC Roots的對象,向下搜索,路徑為引用鏈,當某個對象無法向上搜索到GC Roots,也就是成為GC Roots不可達,則為無用對象。

如果一個對象是GC Roots不可達,則需要經過兩次標記才會進行回收,第一次標記的時候,會判斷是否需要執行finalize方法(沒必要執行的情況:沒實現finalize方法或者已經執行過)。如果需要執行finalize方法,則會放入一個回收隊列中,對於回收隊列中的對象,如果執行finalize方法之後,沒法將對象重新跟GC Roots進行關聯,則會進行回收。

很抽象,對吧,來一個明了的解釋?

比如手機壞了(不可達對象),有錢不在乎就直接拿去回收(這就是沒實現finalize方法),如果已經修過但是修不好了(已經執行過finalize方法),就直接拿去回收站回收掉。如果沒修過,就會拿去維修店(回收隊列)進行維修,實在維修不好了(執行了finalize方法,但是無法連上GC Roots),就會拿去回收站回收掉了。

那什麼對象可以成為GC Roots呢?

1>虛擬機棧中的引用對象

2>本地方法棧中Native方法引用的對象

2>方法區靜態屬性引用對象

3>方法區常量引用對象

(3)對象引用分類

1>強引用:例如實例一個對象,就是即使內存不夠用了,打死都不回收的那種。

2>軟引用:有用非必須對象,內存夠,則不進行回收,內存不夠,則回收。例如A借錢給B,當A還有錢的時候,B可以先不還,A沒錢了,B就必須還了。

3>弱引用:非必須對象,只能存活到下一次垃圾回收前。

4>虛引用:幽靈引用,必須跟引用隊列配合使用,目的是回收前收到系統通知。

下面是java的引用類型結構圖:

(1)軟引用示例

內存夠用的情況:

運行結果:

內存不夠用的情況:

運行結果:

(2)弱引用示例結果:

無論如何都會被回收

(3)虛引用示例:

運行結果:

解釋:為什麼2和5的輸出為null呢,如下

3為null是因為還沒有進行gc,所以對象還沒加入到引用隊列中,在gc後就加入到了引用隊列中,所以6有值。

這個虛引用在GC後會將對象放到引用隊列中,所以可以在對象回收後做相應的操作,判斷對象是否在引用隊列中,可以進行後置通知,類似spring aop的後置通知。

二、垃圾回收發生的區域

垃圾回收主要發生在堆內存裡面,而堆內存又細分為 年輕代 老年代 ,默認情況下年輕代和老年代比例為1:2,比如整個堆內存大小為3G,年輕代和老年代分別就是1G和2G,想要更改這個比例需要修改JVM參數-XX:NewRatio,

比如-XX:NewRatio=4,那老年代:年輕代=4:1。而年輕代又分為Eden區,S0(Survivor From)和S1(Survivor To)區,一般Eden:S0:S1=8:1:1,如果想要更改此比例,則修改JVM參數-XX:SurvivorRatio=4,此時就是Eden:S0:S1=4:1:1。

在年輕代發生GC稱為Young GC,老年代發生GC成為Full GC,Young GC比Full GC頻繁。

解析Young GC:

JVM啟動後,第一次GC,就會把Eden區存活的對象移入S0區;第二次GC就是Eden區和S0一起GC,此時會把存活的對象移入S1區,S0清空;第三次GC就是Eden區和S1區進行GC,會把存活的對象移入S0區,如此往復循環15次(默認),就會把存活的對象存入老年區。

類似與如果有三個桶,編號分別為1(1號桶內的沙子是源源不斷的,就像工地上。你們沒去工地搬過磚可能不知道,但是我真的去工地上搬過啊),2,3。1裡面裝有沙子,需要將沙子篩為細沙。首先將桶1內的沙子篩選一遍過後的放置於桶2,第二次篩選就會將桶1和桶2裡面的沙子一起篩,篩完之後放到桶3內,桶2清空。第三次篩選就會將桶1和桶3的沙子一起篩選,曬完放到桶2內,桶3清空。如此往復循環15次,桶2或桶3裡面的沙子就是合格的沙子,就需要放到備用桶內以待使用。

上述中桶1就是Eden區,桶2就是S0區,桶3就是S1區。

三、垃圾回收演算法

三種,分別是復制演算法,標記-清除演算法,標記-整理演算法。

(1)復制演算法。

其會將內存區域分成同樣大小的兩塊,一塊用來使用,另外一塊在GC的時候存放存活的對象,然後將使用的一塊清除。如此循環往復。

適用於新生代。

優點:沒有內存碎片,缺點:只能使用一般的內存。

(2)標記-清除演算法。

使用所有內存區域,在GC的時候會將需要回收的內存區域先進行標記,然後同意回收。

適用於老年代。

缺點:產生大量內存碎片,會直接導致大對象無法分配內存。

(3)標記-整理演算法。

使用所有內存區域,在GC的時候會先將需要回收的內存區域進行標記,然後將存活對象忘一邊移動,最後將清理掉邊界以外的所有內存。

適用於老年代。

四、GC日誌查看

利用JVM參數-XX:+PrintGCDetails就可以在GC的時候列印出GC日誌。

年輕代GC日誌:

老年代GC日誌:

五、垃圾收集器

主要有四類收集器以及七大收集器

四類:

(1)Serial:單線程收集器,阻塞工作線程,它一工作,全部都得停下。

(2)Paralle:Serial的多線程版本,也是阻塞工作線程

(3)CMS(ConcMarkSweep):並行垃圾收集器,可以和工作線程一起工作。

(4)G1:將堆分成大小一致的區域,然後並發的對其進行垃圾回收。

怎麼查看默認的收集器呢?

用JVM參數-XX:+PrintCommandLineFlags,運行之後會輸出如下參數。可以看到,jdk1.8默認是Parallel收集器。

七大收集器:

(1)Serial:串列垃圾收集器,單線程收集器。用於新生代。用JVM參數-XX:+UseSerialGC開啟,開啟後Young區用Serial(底層復制演算法),Old區用Serial Old(Serial的老年代版本,底層是標記整理演算法)。

(2)ParNew:用於新生代,並行收集器。就是Serial的多線程版本。用JVM參數-XX:+UseParNewGC,young:parnew,復制演算法。Old:serialOld,標記整理演算法。-XX:ParallecGCThreads限制線程回收數量,默認跟cpu數目一樣。只是新生代用並行,老年代用串列。

(3)Parallel Scavenge:並行回收收集器。用JVM參數-XX:+UseParallelGC開啟,young:parallel scavenge(底層是復制演算法),old:parallel old(parallel的老年代版本,底層是標記整理),新生代老年代都用並行回收器。

這個收集器有兩個優點:

可控的吞吐量 :就是工作線程工作90%的時間,回收線程工作10%的時間,即是說有90%的吞吐量。

自適應調節策略 :會動態調節參數以獲取最短的停頓時間。

(4)Parallel Old:Parallel Scavenge的老年代版本,用的是標記整理演算法。用JVM參數-XX:+UseParallelOldGC開啟,新生代用Parallel Scavenge,老年代用Parallel Old

(5)CMS(ConcMarkSweep):並發標記清除。 底層是標記清除演算法,所以會產生內存碎片,同時也會耗cpu。 以獲取最短回收停頓時間為目標。-XX:+UseConcMarkSweep,新生代用ParNew,老年代用CMS。CMS必須在堆內存用完之前進行清除,否則會失敗,這時會調用SerialOld後備收集器。

初始標記和重新標記都會停止工作線程,並發標記和並發清除會跟工作線程一起工作。

(6)SerialOld:老年代串列收集器(以後Hotspot虛擬機會直接移除掉)。

(7)G1:G1垃圾收集器,演算法是標記整理,不會產生內存碎片。橫跨新生代老年代。實現盡量高吞吐量,滿足回收停頓時間更短。

G1可以精確控制垃圾收集的停頓時間,用JVM參數-XX:MaxGCPauseMillis=n,n為停頓時間,單位為毫秒。

區域化內存劃片Region,會把整個堆劃分成同樣大小的區域塊(1MB~32MB),最多2048個內存區域塊,所以能支持的最大內存為32*2048=65535MB,約為64G。

上圖是收集前和收集後的對比,有些對象很大,分割之後就是連續的區域,也即是上圖的Humongous。

上述理論可能有點乏味,下圖很清晰明了(某度找的)。

下面來一張整個垃圾回收機制的思維導圖(太大,分成兩部分)。

=======================================================

我是Liusy,一個喜歡健身的程序猿。

歡迎關注【Liusy01】,一起交流Java技術及健身,獲取更多干貨。

Ⅲ java中的垃圾回收是什麼意思

垃圾回收就是gc(gabage collection)。

java比c++的優點就是多了垃圾回收機制,程序員不用去關心垃圾的回收,系統會自動調用去回收內存。

一般我們想回收的時候只需要調用system.gc方法就可以了。系統會自己去調用destroy方法和其他的回收方法釋放內存,節省內存空間。

Ⅳ 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的虛擬機中一般把內存劃分為新生代和年老代,當新創建對象時一般在新生代中分配內存空間,當新生代垃圾收集器回收幾次之後仍然存活的對象會被移動到年老代內存中,當大對象在新生代中無法找到足夠的連續內存時也直接在年老代中創建。

閱讀全文

與java垃圾回收演算法相關的資料

熱點內容
更新快學習看片網站 瀏覽:604
上海人名廣場解壓博物館 瀏覽:222
nyy. onlie/ index. php/ vohpl 瀏覽:701
行為科學pdf 瀏覽:135
電影最後的演員表是頓號還是空格 瀏覽:501
怎麼鎖pdf 瀏覽:524
手機sd文件夾為空 瀏覽:193
邵氏武打功夫片大全 瀏覽:230
抖音電影音樂榜單 瀏覽:674
jquery旋轉木馬特效源碼 瀏覽:428
電影永恆無刪減版185 瀏覽:720
完美世界的後續小說 瀏覽:4
台灣電影埃及場景 瀏覽:806
華為的親情關懷app哪裡下載 瀏覽:488
win8定時關機命令 瀏覽:612
榮耀手機電池app耗電量如何隱藏 瀏覽:322
Win10開機啟動項命令 瀏覽:949
兒女傳奇所有電影資源 瀏覽:847
葉子楣跟徐錦江電影 瀏覽:318
十大封禁鬼片國產 瀏覽:559