摘要:根搜索算法它的處理方式就是,設(shè)立若干種根對象,當(dāng)任何一個根對象到某一個對象均不可達時,則認為這個對象是可以被回收的。
引用計數(shù)算法
給對象中添加一個引用計數(shù)器,每當(dāng)有一個地方引用它時,計數(shù)器值就加1;當(dāng)引用失效時,計數(shù)器值就減1;任何時刻計數(shù)器為0的對象就是不可能再被使用的。
缺點:引用和去引用伴隨加法和減法,影響性能。
致命的缺陷:對于循環(huán)引用的對象無法進行回收。
它的處理方式就是,設(shè)立若干種根對象,當(dāng)任何一個根對象到某一個對象均不可達時,則認為這個對象是可以被回收的。
可達性分析:從根(GC Roots)的對象作為起始點,開始向下搜索,搜索所走過的路徑稱為“引用鏈”,當(dāng)一個對象到GC Roots沒有任何引用鏈相連(用圖論的概念來講,就是從GC Roots到這個對象不可達)時,則證明此對象是不可用的。
在JAVA語言中,可以當(dāng)做GC roots(GC根)的對象有以下幾種:
棧(棧幀中的本地變量表)中引用的對象。
方法區(qū)中的靜態(tài)成員。
方法區(qū)中的常量引用的對象(全局變量)。
本地方法棧中JNI(一般說的Native方法)引用的對象。
第一和第四種都是指的方法的本地變量表,第二種表達的意思比較清晰,第三種主要指的是聲明為final的常量值。
標記清除算法當(dāng)堆中的有效內(nèi)存空間(available memory)被耗盡的時候,就會停止整個程序(也被成為stop the world),然后進行兩項工作,第一項則是標記,第二項則是清除。
標記:標記的過程其實就是,遍歷所有的GC Roots,然后將所有GC Roots可達的對象標記為存活的對象。
清除:清除的過程將遍歷堆中所有的對象,將沒有標記的對象全部清除掉。
沒有被標記的對象將會回收清除掉,而被標記的對象將會留下,并且會將標記位重新歸0
標記-清除算法的缺點:
首先,它的缺點就是效率比較低(遞歸與全堆對象遍歷),導(dǎo)致stop the world的時間比較長,尤其對于交互式的應(yīng)用程序來說簡直是無法接受。
第二點主要的缺點,則是這種方式清理出來的空閑內(nèi)存是不連續(xù)的,這點不難理解,我們的死亡對象都是隨即的出現(xiàn)在內(nèi)存的各個角落的,現(xiàn)在把它們清除之后,內(nèi)存的布局自然會亂七八糟。而為了應(yīng)付這一點,JVM就不得不維持一個內(nèi)存的空閑列表,這又是一種開銷。而且在分配數(shù)組對象的時候,尋找連續(xù)的內(nèi)存空間會不太好找。
復(fù)制算法:(新生代的GC)將原有的內(nèi)存空間分為兩塊,每次只使用其中一塊,在垃圾回收時,將正在使用的內(nèi)存中的存活對象復(fù)制到未使用的內(nèi)存塊中,之后,清除正在使用的內(nèi)存塊中的所有對象,交換兩個內(nèi)存的角色,完成垃圾回收。
將內(nèi)存分為一塊比較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。當(dāng)回收時,將Eden和Survivor中還存活著的對象一次性地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。
當(dāng)Survivor空間不夠用時,需要依賴于老年代進行分配擔(dān)保,所以大對象直接進入老年代
標記-整理算法:(老年代的GC)和標記-清除算法一樣,標記-壓縮算法也首先需要從根節(jié)點開始,對所有可達對象做一次標記;但之后,它并不簡單的清理未標記的對象,而是將所有的存活對象壓縮到內(nèi)存的一端;之后,清理邊界外所有的空間。
標記:它的第一個階段與標記/清除算法是一模一樣的,均是遍歷GC Roots,然后將存活的對象標記。
整理:移動所有存活的對象,且按照內(nèi)存地址次序依次排列,然后將末端內(nèi)存地址以后的內(nèi)存全部回收。因此,第二階段才稱為整理階段。
標記-清除算法、復(fù)制算法、標記整理算法的總結(jié):三個算法都基于根搜索算法去判斷一個對象是否應(yīng)該被回收,而支撐根搜索算法可以正常工作的理論依據(jù),就是語法中變量作用域的相關(guān)內(nèi)容。因此,要想防止內(nèi)存泄露,最根本的辦法就是掌握好變量作用域,而不應(yīng)該使用C/C++式內(nèi)存管理方式。
在GC線程開啟時,或者說GC過程開始時,它們都要暫停應(yīng)用程序(stop the world)。
它們的區(qū)別如下:(>表示前者要優(yōu)于后者,=表示兩者效果一樣)
效率:復(fù)制算法>標記/整理算法>標記/清除算法(此處的效率只是簡單的對比時間復(fù)雜度,實際情況不一定如此)。
內(nèi)存整齊度:復(fù)制算法=標記/整理算法>標記/清除算法。
內(nèi)存利用率:標記/整理算法=標記/清除算法>復(fù)制算法。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/70075.html
摘要:本文詳細描述了堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對理解內(nèi)存結(jié)構(gòu)有所幫助。該區(qū)域也稱為內(nèi)存模型的本地區(qū)。在中,內(nèi)存泄露是指對象已不再使用,但垃圾回收未能將他們視做不使用對象予以回收。 本文詳細描述了 Java 堆內(nèi)存模型,垃圾回收算法以及處理內(nèi)存泄露的最佳方案,并輔之以圖表,希望能對理解 Java 內(nèi)存結(jié)構(gòu)有所幫助。原文作者 Sumith Puri,...
摘要:直接對棧的操作只有兩個,就是對棧幀的壓棧和出棧。中將永久代移除,同時增加元數(shù)據(jù)區(qū)。在中,本地方法棧和虛擬機棧是在同一塊兒區(qū)域,這完全取決于技術(shù)實現(xiàn)的決定,并未在規(guī)范中強制。 原文:https://github.com/linsheng97... 描述一下 JVM 的內(nèi)存區(qū)域 程序計數(shù)?(PC,Program Counter Register)。在 JVM 規(guī)范中,每個線程都有它自己的...
摘要:在這種消耗很高的狀態(tài)下,應(yīng)用程序所有的線程都會掛起,暫停一切正常的工作,等待垃圾回收的完成。但是,因為線程切換和上下文轉(zhuǎn)換的消耗,會使得垃圾回收的總體成本上升,造成系統(tǒng)吞吐量的下降。 Java 垃圾回收(GC) 泛讀 文章地址: https://segmentfault.com/a/1190000008922319 0. 序言 帶著問題去看待 垃圾回收(GC) 會比較好,一般來說主要的...
閱讀 3011·2021-10-27 14:15
閱讀 2999·2021-09-07 10:18
閱讀 1320·2019-08-30 15:53
閱讀 1570·2019-08-26 18:18
閱讀 3373·2019-08-26 12:15
閱讀 3460·2019-08-26 10:43
閱讀 654·2019-08-23 16:43
閱讀 2207·2019-08-23 15:27