下圖是Java代碼編譯的詳細流程(即,javac的執行過程),瞭解便可,通常只要知道java文件是經過javac命令編譯成class文件,再經過java命令運行的就能夠了,如:java
javac Hello.java
java Hello
複製代碼
java中的內存管理指的是下圖中「內存空間」部分的內存操做。算法
做用:存放java方法執行時全部的數據。 組成:由棧幀組成,一個棧幀表明一個方法的執行。spa
Java棧幀:每一個方法從調用到執行完成就對應一個棧幀在虛擬機棧中入棧到出棧。它描述了一個方法的局部變量表、棧操做數、動態連接、方法出口。線程
與Java棧區基於一致。指針
做用:本地方法棧是專門爲native方法服務的。code
存儲被虛擬機加載的類信息、常量、靜態常量、即時編譯器編譯後等數據(這些數據在程序啓動後會永遠佔據內存)。cdn
做用:全部經過new建立的對象的內存都在堆中分配。 特色:是虛擬機中最大的一塊內存,是GC要回收的部分。對象
對於堆區,其內存結構還有些不同的地方,先看下圖:blog
簡單來講,堆區分爲新生代(Young Generation)與老年代(Old Generation),程序在創始對象時,對象會先被分配到新生代中,當新生代區內存不足時,JVM會經過必定的算法規則將新生代中的對象轉移至老年代中,當新生代與老年代都沒有足夠的內存空間時,JVM就會拋出OOM異常。內存
在內存建立對象的同時,會爲它建立一個引用記數器,並將引用記數器加1,每次有引用引用到此對象時,記數器就會累計加1,而當其中一個引用銷燬時,記數器就會減1,當引用記數器爲0時,說明該對象已是垃圾對象,下次gc時,對象就會被回收了。
弊端: 對象A與對象B互相引用時,這2個對象的引用記數器永遠是正數,當這2個對象都沒有被其餘對象所引用時(對象不可達),會由於它們的引用記數器不爲0致使它們不會被gc回收。
也稱爲根搜索算法。把程序全部的引用關係看作是一張圖(有向圖),從GC Root節點開始尋找全部的引用節點,當全部的引用節點尋找完畢以後,剩餘的節點被認爲是沒有引用的節點,即不可達的節點,就是垃圾對象。
上圖中ObjD、E、F由於沒有路徑可達,因此是垃圾對象。
java中的引用類型有4種:強引用、軟引用、弱引用、虛引用。其中,強引用和弱引用在開發中最經常使用。
弱引用的建立
// 強引用
Object obj = new Object();
// 弱引用,此時obj與wf都引用了Object對象
WeakReference<Object> wf = new WeakReference<Object>(obj);
// 斷開強引用,此時只有wf引用這個Object對象
obj = null;
// 通用弱引用獲取Object對象(可能爲null)
wf.get();
複製代碼
在使用wf.get()時,要判斷獲取到的對象是否爲null,由於弱引用不會阻止對象的回收。
從根集合遍歷全部的引用,上圖中,根集合引用了A,A引用了C,B是不可達的對象引用,在掃描階段中,B會被標記爲垃圾對象,當垃圾回收機制執行時,會直接將B對象置爲空,此時內存塊中就只剩下A、C對象引用,B就被垃圾回收給回收掉了。 優勢:不須要進行對象的移動,僅對不存活的對象進行處理,在存活對象比較多的狀況下極爲高效。 缺點:因爲標記-清除算法會直接回收掉不存活的對象,會形成內在碎片,不利於後續對象的分配
從根集合開始遍歷,上圖中,遍歷到A時是可達的,就把A複製到另外一塊空閒的內存中,繼續遍歷,發現B不可達,直接跳過,日後,發現C可達,就把C一樣地複製到這塊空閒內存中,等全部複製都處理完時,把原來的內存空間清空,只保留複製後的這塊內存空間。 優勢:當存活對象比較少時,極爲高效,且不會有產生內存碎片。 缺點:須要一塊內存做爲交換空間來進行對象的移動。
從根集合開始遍歷,經過對整個內存區的掃描,將可回收對象掃描出來,上圖中,到了第二階段,就將B標記爲可回收對象,到了第三個階段,直接掃描並消除內存中被標記的對象,同時,在回收不存活對象佔用的空間時,會將內存中全部存活對象往左端空閒處移動,並更新對應的指針。
這三種算法各有優劣,JVM在處理垃圾時會整合去使用,並非只使用其中某個算法。當內存中存活的對象比較少時,採用「複製算法」去處理垃圾對象;當內存中存活的對象比較多時,會採用「標記-整理算法」或「標記-清除算法」去處理垃圾對象。