本文目錄一覽:
簡述java垃圾回收機制原理
回收機制就是 當一些資源被創建使用之後或不在調用的話 就會變成垃圾,垃圾的話會佔用空間,這時候就需要釋放空間給其他程序使用,所以JAVA擁有自動垃圾回收機制。
GC的工作原理: 引用計數,標記複製”引用計數”是一種簡單但速度很慢的垃圾回收技術.
“標記複製”的運行機制,垃圾回收器遍歷包含所有引用的列表,當發現存活的對象引用時做上標記,這樣當遍歷完所有對象引用並做上標記的時候,執行垃圾回收,將沒有標記的對象堆空間釋放.
垃圾回收機制的優點:Java的垃圾回收機制使得java程序員不用擔心內存空間的分配,減少了內存溢出.但同時也犧牲了一定的性能.
java的垃圾回收機制是什麼?
Java 引入了垃圾回收機制,由於有個垃圾回收機制,Java中的對象不再有「作用域」的概念,只有對象的引用才有「作用域」。垃圾回收可以有效的防止內存泄露,有效的使用可以使用的內存。垃圾回收器通常是作為一個單獨的低級別的線程運行,不可預知的情況下對內存堆中已經死亡的或者長時間沒有使用的對象進行清除和回收,程序員不能實時的調用垃圾回收器對某個對象或所有對象進行垃圾回收。回收機制有分代複製垃圾回收和標記垃圾回收,增量垃圾回收。
java垃圾回收機制
全面分析Java的垃圾回收機制
Java的堆是一個運行時數據區,類的實例(對象)從中分配空間。Java虛擬機(JVM)的堆中儲存著正在運行的應用程序所建立的所有對象,這些對象通過new、newarray、anewarray和multianewarray等指令建立,但是它們不需要程序代碼來顯式地釋放。一般來說,堆的是由垃圾回收 來負責的,儘管JVM規範並不要求特殊的垃圾回收技術,甚至根本就不需要垃圾回收,但是由於內存的有限性,JVM在實現的時候都有一個由垃圾回收所管理的堆。垃圾回收是一種動態存儲管理技術,它自動地釋放不再被程序引用的對象,按照特定的垃圾收集演算法來實現資源自動回收的功能。
垃圾收集的意義
在C++中,對象所佔的內存在程序結束運行之前一直被佔用,在明確釋放之前不能分配給其它對象;而在Java中,當沒有對象引用指向原先分配給某個對象的內存時,該內存便成為垃圾。JVM的一個系統級線程會自動釋放該內存塊。垃圾收集意味著程序不再需要的對象是”無用信息”,這些信息將被丟棄。當一個對象不再被引用的時候,內存回收它佔領的空間,以便空間被後來的新對象使用。事實上,除了釋放沒用的對象,垃圾收集也可以清除內存記錄碎片。由於創建對象和垃圾收集器釋放丟棄對象所佔的內存空間,內存會出現碎片。碎片是分配給對象的內存塊之間的空閑內存洞。碎片整理將所佔用的堆內存移到堆的一端,JVM將整理出的內存分配給新的對象。
垃圾收集能自動釋放內存空間,減輕編程的負擔。這使Java 虛擬機具有一些優點。首先,它能使編程效率提高。在沒有垃圾收集機制的時候,可能要花許多時間來解決一個難懂的存儲器問題。在用Java語言編程的時候,靠垃圾收集機制可大大縮短時間。其次是它保護程序的完整性, 垃圾收集是Java語言安全性策略的一個重要部份。
垃圾收集的一個潛在的缺點是它的開銷影響程序性能。Java虛擬機必須追蹤運行程序中有用的對象, 而且最終釋放沒用的對象。這一個過程需要花費處理器的時間。其次垃圾收集演算法的不完備性,早先採用的某些垃圾收集演算法就不能保證100%收集到所有的廢棄內存。當然隨著垃圾收集演算法的不斷改進以及軟硬體運行效率的不斷提升,這些問題都可以迎刃而解。
垃圾收集的演算法分析
Java語言規範沒有明確地說明JVM使用哪種垃圾回收演算法,但是任何一種垃圾收集演算法一般要做2件基本的事情:(1)發現無用信息對象;(2)回收被無用對象佔用的內存空間,使該空間可被程序再次使用。
大多數垃圾回收演算法使用了根集(root set)這個概念;所謂根集就量正在執行的Java程序可以訪問的引用變數的集合(包括局部變數、參數、類變數),程序可以使用引用變數訪問對象的屬性和調用對象的方法。垃圾收集首選需要確定從根開始哪些是可達的和哪些是不可達的,從根集可達的對象都是活動對象,它們不能作為垃圾被回收,這也包括從根集間接可達的對象。而根集通過任意路徑不可達的對象符合垃圾收集的條件,應該被回收。下面介紹幾個常用的演算法。
1、 引用計數法(Reference Counting Collector)
引用計數法是唯一沒有使用根集的垃圾回收的法,該演算法使用引用計數器來區分存活對象和不再使用的對象。一般來說,堆中的每個對象對應一個引用計數器。當每一次創建一個對象並賦給一個變數時,引用計數器置為1。當對象被賦給任意變數時,引用計數器每次加1當對象出了作用域後(該對象丟棄不再使用),引用計數器減1,一旦引用計數器為0,對象就滿足了垃圾收集的條件。
基於引用計數器的垃圾收集器運行較快,不會長時間中斷程序執行,適宜地必須 實時運行的程序。但引用計數器增加了程序執行的開銷,因為每次對象賦給新的變數,計數器加1,而每次現有對象出了作用域生,計數器減1。
2、tracing演算法(Tracing Collector)
tracing演算法是為了解決引用計數法的問題而提出,它使用了根集的概念。基於tracing演算法的垃圾收集器從根集開始掃描,識別出哪些對象可達,哪些對象不可達,並用某種方式標記可達對象,例如對每個可達對象設置一個或多個位。在掃描識別過程中,基於tracing演算法的垃圾收集也稱為標記和清除(mark-and-sweep)垃圾收集器.
3、compacting演算法(Compacting Collector)
為了解決堆碎片問題,基於tracing的垃圾回收吸收了Compacting演算法的思想,在清除的過程中,演算法將所有的對象移到堆的一端,堆的另一端就變成了一個相鄰的空閑內存區,收集器會對它移動的所有對象的所有引用進行更新,使得這些引用在新的位置能識別原來 的對象。在基於Compacting演算法的收集器的實現中,一般增加句柄和句柄表。
4、copying演算法(Coping Collector)
該演算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分成 一個對象 面和多個空閑面, 程序從對象面為對象分配空間,當對象滿了,基於coping演算法的垃圾 收集就從根集中掃描活動對象,並將每個 活動對象複製到空閑面(使得活動對象所佔的內存之間沒有空閑洞),這樣空閑面變成了對象面,原來的對象面變成了空閑面,程序會在新的對象面中分配內存。
一種典型的基於coping演算法的垃圾回收是stop-and-copy演算法,它將堆分成對象面和空閑區域面,在對象面與空閑區域面的切換過程中,程序暫停執行。
5、generation演算法(Generational Collector)
stop-and-copy垃圾收集器的一個缺陷是收集器必須複製所有的活動對象,這增加了程序等待時間,這是coping演算法低效的原因。在程序設計中有這樣的規律:多數對象存在的時間比較短,少數的存在時間比較長。因此,generation演算法將堆分成兩個或多個,每個子堆作為對象的一代(generation)。由於多數對象存在的時間比較短,隨著程序丟棄不使用的對象,垃圾收集器將從最年輕的子堆中收集這些對象。在分代式的垃圾收集器運行後,上次運行存活下來的對象移到下一最高代的子堆中,由於老一代的子堆不會經常被回收,因而節省了時間。
6、adaptive演算法(Adaptive Collector)
在特定的情況下,一些垃圾收集演算法會優於其它演算法。基於Adaptive演算法的垃圾收集器就是監控當前堆的使用情況,並將選擇適當演算法的垃圾收集器。
JAVA垃圾回收器如何工作
java回收器有gc
以下是工作原理:
強引用(StrongReference)
這個就不多說,我們寫代碼天天在用的就是強引用。如果一個對象被被人擁有強引用,那麼垃圾回收器絕不會回收它。當內存空間不足,Java 虛擬機寧願拋出 OutOfMemoryError 錯誤,使程序異常終止,也不會靠隨意回收具有強引用的對象來解決內存不足問題。
Java 的對象是位於 heap 中的,heap 中對象有強可及對象、軟可及對象、弱可及對象、虛可及對象和不可到達對象。應用的強弱順序是強、軟、弱、和虛。對於對象是屬於哪種可及的對象,由他的最強的引用決定。如下
代碼:
String abc=new String(“abc”); //1
SoftReferenceString softRef=new SoftReferenceString(abc); //2
WeakReferenceString weakRef = new WeakReferenceString(abc); //3
abc=null; //4
softRef.clear();//5
第一行在 heap 堆中創建內容為「abc」的對象,並建立 abc 到該對象的強引用,該對象是強可及的。
第二行和第三行分別建立對 heap 中對象的軟引用和弱引用,此時 heap 中的 abc 對象已經有 3 個引用,顯然此時 abc 對象仍是強可及的。
第四行之後 heap 中對象不再是強可及的,變成軟可及的。
第五行執行之後變成弱可及的。
軟引用(SoftReference)
如果一個對象只具有軟引用,那麼如果內存空間足夠,垃圾回收器就不會回收它,如果內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就可以被程序使用。軟引用可用來實現內存敏感的高速緩存。
軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收,Java 虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
軟引用是主要用於內存敏感的高速緩存。在 jvm 報告內存不足之前會清除所有的軟引用,這樣以來 gc 就有可能收集軟可及的對象,可能解決內存吃緊問題,避免內存溢出。什麼時候會被收集取決於 gc 的演算法和 gc 運行時可用內存的大小。當 gc 決定要收集軟引用時執行以下過程,以上面的 softRef 為例:
1 首先將 softRef 的 referent(abc)設置為 null,不再引用 heap 中的 new String(“abc”)對象。
2 將 heap 中的 new String(“abc”)對象設置為可結束的(finalizable)。
3 當 heap 中的 new String(“abc”)對象的 finalize()方法被運行而且該對象佔用的內存被釋放, softRef
被添加到它的 ReferenceQueue(如果有的話)中。
注意:對 ReferenceQueue 軟引用和弱引用可以有可無,但是虛引用必須有。
被 Soft Reference 指到的對象,即使沒有任何 Direct Reference,也不會被清除。一直要到 JVM 內存
不足且沒有 Direct Reference 時才會清除,SoftReference 是用來設計 object-cache 之用的。如此一來
SoftReference 不但可以把對象 cache 起來,也不會造成內存不足的錯誤 (OutOfMemoryError)。
弱引用(WeakReference)
如果一個對象只具有弱引用, 那該類就是可有可無的對象, 因為只要該對象被 gc 掃描到了隨時都會把它幹掉。弱引用與軟引用的區別在於:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內存區域的過程中,一旦發現了只具有弱引用的對象,不管當前內存空間足夠與否,都會回收它的內存。不過,由於垃圾回收器是一個優先順序很低的線程, 因此不一定會很快發現那些只具有弱引用的對象。弱引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果弱引用所引用的對象被垃圾回收,Java 虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
虛引用(PhantomReference)
“虛引用”顧名思義,就是形同虛設,與其他幾種引用都不同,虛引用並不會決定對象的生命周期。如果一個
對象僅持有虛引用,那麼它就和沒有任何引用一樣,在任何時候都可能被垃圾回收。虛引用主要用來跟蹤對象被
垃圾回收的活動。
虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之關聯的引用隊列中。程序可以通過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序如果發現某個虛引用已經被加入到引用隊列,那麼就可以在所引用的對象的內存被回收之前採取必要的行動。
建立虛引用之後通過 get 方法返回結果始終為 null,通過源代碼你會發現,虛引用通向會把引用的對象寫進
referent,只是 get 方法返回結果為 null。先看一下和 gc 交互的過程再說一下他的作用。
1 不把 referent 設置為 null, 直接把 heap 中的 new String(“abc”)對象設置為可結束的(finalizable)。
2 與軟引用和弱引用不同, 先把 PhantomRefrence 對象添加到它的 ReferenceQueue 中.然後在釋放虛可及的對象。
原創文章,作者:簡單一點,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/127595.html