對於GC來講,當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。一般,GC採用有向圖的方式記錄和管理堆(heap)中的全部對象,經過這種方式肯定哪些對象是"可達的", 哪些對象是"不可達的"。可是,爲了保證GC可以在不一樣平臺實現的問題,Java規範對GC的不少行爲都沒有進行嚴格的規定。例如,對於採用什麼類型的回收算法、何時進行回收等重要問題都沒有明確的規定。所以,不一樣的JVM的實現者往 往有不一樣的實現算法。(釋放對象時,只要將對象全部引用賦值爲null)java
-----------------------------------------------------------------------------------------------------------------程序員
垃圾回收回收的對象佔據的內存空間而不是對象。算法
垃圾回收的目的是識別而且丟棄應用再也不使用的對象來釋放和重用資源。當對象在JVM運行空間中沒法經過根集合到達(找到)時,這個對象被稱爲垃圾對象,這個對象就能夠被回收了。根集合是由類中的靜態引用域與本地引用域組成的,JVM經過根集合索引對象。 在釋放對象佔用的內存以前,垃圾收集器會調用對象的finalize()方法,通常建議在該方法中釋放對象持有的資源。若是對象的引用被置爲null,垃圾收集器不會當即釋放對象佔用的內存,在下一個垃圾回收週期中,這個對象將是可被回收的。調用system.gc()方法會大大的影響系統性能。bootstrap
--------------------------------------------------------------------------------------------------------------數組
通常狀況下關注於兩中內容:堆內存與棧內存。堆內存主要用來存儲程序在運行時建立或實例化的對象與變量,例如經過new關鍵字建立的對象。而棧內存則是用來存儲程序代碼中聲明爲靜態或非靜態的方法。 緩存
Java的堆更像一個傳送帶,每分配一個新對象,它就往前移動一格。這意味着對象存儲空間的分配速度至關快。Java的「堆指針」只是簡單地移動到還沒有分配的領域。也就是說,分配空間的時候,「堆指針」只管依次往前移動而無論後面的對象是否還要被釋放掉。若是可用內存耗盡以前程序就退出就再好不過了,這樣的話垃圾回收器壓根就不會被激活。安全
棧是留給JVM本身用的,用來存放類的信息的,它和堆不一樣,運行期內GC不會釋放空間,當超過變量的做用域後,java會自動釋放掉爲該變量所分配的內存空間:jvm
一、若是程序聲明瞭static的變量,就直接在棧中運行的,進程銷燬了,不必定會銷燬static變量。
二、在函數中定義的基本類型變量和對象的引用變量都在函數的棧內存中分配函數
堆的優點是能夠動態分配內存大小,生存期也沒必要事先告訴編譯器,由於它是在運行時動態分配內存的。缺點就是要在運行時動態分配內存,存取速度較慢。
棧的優點是存取速度比堆要快,缺點是存在棧中的數據大小與生存期必須是肯定的無靈活性。性能
------------------------------------------------------------------------------------------------------------------------------------------------------------
JVM的堆是運行時數據區,全部類的實例和數組都是在堆上分配內存。它在JVM啓動的時候被建立。對象所佔的堆內存是由自動內存管理系統也就是垃圾收集器回收。堆內存是由存活和死亡的對象組成的。存活的對象是應用能夠訪問的,不會被垃圾回收。死亡的對象是應用不可訪問尚且尚未被垃圾收集器回收掉的對象。一直到垃圾收集器把這些對象回收掉以前,他們會一直佔據堆內存空間。
---------------------------------------------------------------------------------------------------------------
在JVM運行空間中,對象的整個生命週期大體能夠分爲7個階段:
建立階段;(1)爲對象分配存儲空間; (2) 開始構造對象; (3) 從超類到子類對static成員進行初始化; (4)超類成員變量按順序初始化,遞歸調用超類的構造方法;(5)子類成員變量按順序初始化,子類構造方法調用。
應用階段;此階段的特色:(1)系統維護着對象的>=1個強引用(Strong Reference); (2)全部對該對象的引用所有是強引用(除非咱們顯示地適用了:軟引用(Soft Reference)、弱引用(Weak Reference)或虛引用(Phantom Reference)).
-----------------------
強引用:通常的引用都是強引用。經過用new 方式建立的對象,而且顯示關聯的對象。
軟引用:只有當內存不夠的時候,纔回收這類內存,所以內存足夠時它們一般不被回收,若是內存空間不足了,就會回收這些對象的內存。軟引用可用來實現內存敏感的高速緩存。
弱引用:在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。弱引用與軟引用的區別在於,只具備弱引用的對象擁有更短暫的生命週期。
虛引用:虛引用並不會決定對象的生命週期,指一些執行完了finalize函數,併爲不可達對象,可是尚未被GC回收的對象。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。虛引用主要用來跟蹤對象被垃圾回收的活動。這種對象能夠輔助finalize進行一些後期的回收工做,咱們經過覆蓋了Refernce的clear()方法,加強資源回收機制的靈活性。 虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是否已經加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。
在實際程序設計中通常不多使用弱引用和虛引用,是用軟引用的狀況較多,由於軟引用能夠加速JVM對垃圾內存的回收速度,能夠維護系統的運行安全,防止內存溢出等問題的產生。
-------------------
不可視階段; 在其餘區域的代碼中已經不能夠在引用它,其強引用已經消失。
不可到達階段; (有兩種方法來知道這個對象有沒有被引用:第一種是遍歷堆上的對象找引用;第二種是遍歷堆棧或靜態存儲區的引用找對象。Java採用的是後者)在虛擬機的對象引用根集合中再也找不到直接或間接地強引用,這些對象通常是全部線程棧中的臨時變量。全部已經裝載的靜態變量或者是對本地代碼接口的引用。
可收集階段;
終結階段;
釋放階段
<1> 回收器發現該對象已經不可達。
<2> finalize方法已經被執行。
<3> 對象空間已被重用。
-------------------------------------------------------------------------------------------------------------
垃圾回收算法:
Mark-Sweep(標記-清除)算法:兩個階段:標記階段和清除階段。標記階段的任務是標記出全部須要被回收的對象,清除階段就是回收被標記的對象所佔用的空間。容易產生內存碎片。
Copying(複製)算法:它將可用內存按容量劃分爲大小相等的兩塊,每次只使用其中的一塊。當這一塊的內存用完了,就將還存活着的對象複製到另一塊上面,而後再把已使用的內存空間一次清理掉,這樣一來就不容易出現內存碎片的問題。內存縮減到原來的一半。Copying算法的效率跟存活對象的數目多少有很大的關係,若是存活對象不少,那麼Copying算法的效率將會大大下降。
Mark-Compact(標記-整理)算法:標記階段和Mark-Sweep同樣,可是在完成標記以後,它不是直接清理可回收對象,而是將存活對象都向一端移動,而後清理掉端邊界之外的內存。
Generational Collection(分代收集)算法:它的核心思想是根據對象存活的生命週期將內存劃分爲若干個不一樣的區域。通常狀況下將堆區劃分爲老年代(Tenured Generation,每次垃圾收集時只有少許對象須要被回收)和新生代(Young Generation,每次垃圾回收時都有大量的對象須要被回收),那麼就能夠根據不一樣代的特色採起最適合的收集算法。
------------------------------------------------------------------------------------------------------------------
新生代都採起Copying算法,由於新生代中每次垃圾回收都要回收大部分對象,也就是說須要複製的操做次數較少,可是實際中並非按照1:1的比例來劃分新生代的空間的,通常來講是將新生代劃分爲一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden空間和其中的一塊Survivor空間,當進行回收時,將Eden和Survivor中還存活的對象複製到另外一塊Survivor空間中,而後清理掉Eden和剛纔使用過的Survivor空間。
老年特色是每次回收都只回收少許對象,通常使用的是Mark-Compact算法。】
新生代:新建立的對象都存放在這裏。由於大多數對象很快變得不可達,因此大多數對象在年輕代中建立,而後消失。當對象從這塊內存區域消失時,咱們說發生了一次「minor GC」。
老年代:沒有變得不可達,存活下來的年輕代對象被複制到這裏。這塊內存區域通常大於年輕代。由於它更大的規模,GC發生的次數比在年輕代的少。對象從老年代消失時,咱們說「major GC」(或「full GC」)發生了。
新生帶——>老年代
年輕代總共有3塊空間,其中2塊爲Survivor區。各個空間的執行順序以下:
------------------------------------------------------------------------------------------------------------------------------------
Java虛擬機採用一種「自適應」的垃圾回收技術
Java有兩種方找到的存活對象:
(1)中止-複製: 先暫停程序的運行(因此它不屬於後臺回收模式),而後將全部存活的對象從當前堆複製到另外一個堆,沒有被複制的全是垃圾。
(2)標記-清掃:從堆棧和靜態存儲區出發,遍歷全部的引用,進而找出全部存活的對象。每當它找到一個存活對象,就會給對象一個標記。這個過程當中不會回收任何對象。
自適應:當垃圾回收器第一次啓動時,它執行的是「中止-複製」,由於這個時刻內存有太多的垃圾。而後Java虛擬機會進行監視,若是全部對象都很穩定,垃圾回收器的效率下降的話,就切換到「標記-清掃」方式;一樣,Java虛擬機會跟蹤「標記-清掃」效果,要是堆空間出現不少碎片,就會切換到「中止-複製」方式。這就是所謂的「自適應」技術。
--------------------------------------------------------------------------------------------------------------------------------------
每一個對象上都有一個引用計數,對象每被引用一次,引用計數器就+1,對象引用被釋放,引用計數器-1,直到對象的引用計數爲0,對象就標識能夠回收。
這種算法目前定義了幾個root,也就是這幾個對象是jvm虛擬機不會被回收的對象,因此這些對象引用(強引用)的對象都是在使用中的對象,這些對象未使用的對象就是即將要被回收的對象。簡單就是說:若是對象可以達到root,就不會被回收,若是對象不可以達到root,就會被回收。
如下對象會被認爲是root對象:
----------------------------------------------------------------------------------------------------------------------------