您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關Java內存機制和GC回收機制是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
Java代碼執行和編譯的過程
Java內存管理
java內存模型劃分
對象的訪問定位
Object obj = new Object();
java對象創建及初始化
java對象創建之后,就會在堆內存擁有自己的一塊區域,接著就是對象的初始化過程。類成員初始化順序總結:先靜態后普通再構造, 先父類后子類,同級看書寫順序
先執行父類靜態變量和靜態代碼塊,再執行子類靜態變量和靜態代碼塊
先執行父類普通變量和代碼塊,再執行父類構造器(static方法)
先執行子類普通變量和代碼塊,再執行子類構造器(static方法)
static方法初始化先于普通方法,靜態初始化只有在必要時刻才進行且只初始化一次。
注意:子類的構造方法,不管這個構造方法帶不帶參數,默認的它都會先去尋找父類的不帶參數的構造方法。如果父類沒有不帶參數的構造方法,那么子類必須用supper關鍵子來調用父類帶參數的構造方法,否則編譯不能通過。
GC回收機制
java中垃圾回收器可以自動回收無用對象占據的內存,但它只負責釋放java中創建的對象所占據的所有內存,通過某種創建對象之外的方式為對象分配的內存空間則無法被垃圾回收器回收;而且垃圾回收本身也有開銷,GC的優先級比較低,所以如果JVM沒有面臨內存耗盡,它是不會去浪費資源進行垃圾回收以恢復內存的。最后我們會發現,只要程序沒有瀕臨存儲空間用完那一刻,對象占用的空間就總也得不到釋放。我們可以通過代碼System.gc()來主動啟動一個垃圾回收器(雖然JVM不會立刻去回收),在釋放new分配內存空間之前,將會通過finalize()釋放用其他方法分配的內存空間。
哪些內存需要回收
java堆、方法區的內存
什么時候回收
引用計數法
給對象添加一個引用計數器,每當有一個地方引用它時,計數器加一。反之每當一個引用失效時,計數器減一。當計數器為0時,則表示對象不被引用。舉個例子:
但是,引用計數法不能解決對象之間的循環引用,見下例
可達性分析
設立若干根對象(GC Root),每個對象都是一個子節點,當一個對象找不到根時,就認為該對象不可達。
沒有一條從根到Object4 和 Object5的路徑,說明這兩個對象到根是不可達的,可以被回收。java中,可以作為GC Roots的對象包括:java虛擬機棧中引用的對象;方法區中靜態變量引用的對象;方法區中常量引用的對象;本地方法棧中引用的對象。
怎么回收
標記——清除算法
先標記所有需要回收的對象,在標記完成后統一回收所有被標記的對象。
該算法有兩個問題:1)標記和清除過程效率不高。主要由于垃圾收集器需要從GC Roots根對象中遍歷所有可達的對象,并給這些對象加上一個標記,表明此對象在清除的時候被跳過,然后在清除階段,垃圾收集器會從Java堆中從頭到尾進行遍歷,如果有對象沒有被打上標記,那么這個對象就會被清除。顯然遍歷的效率是很低的;2)會產生很多不連續的空間碎片,所以可能會導致程序運行過程中需要分配較大的對象的時候,無法找到足夠的內存而不得不提前出發一次垃圾回收。
復制算法
將內存分為兩塊,每次只使用一塊。當這一塊內存滿了,就將還存活的對象復制到另一塊上,并且嚴格按照內存地址排列,然后把已使用的那塊內存統一回收。
優點是:能夠得到連續的內存空間
缺點是:浪費了一半內存
現代的JVM并不是按照1:1劃分內存空間的,而是將內存分為一塊較大的Eden區和兩塊較小的Survivor區,每次使用其中的Eden和一塊Survivor區。當回收的時候,將Eden和Survivor中還存活著的對象一次性復制到另外一塊Survivor中,最后把Eden和Survivor的空間清理出來。其實這里還有一個問題:就是如果垃圾回收后,存活的對象需要的空間大于剩余一塊Survivor的空間怎么辦?答案是需要依賴其他內存進行分配(這里主要指的是老年代)。
標記-整理算法
與標記-清除算法過程一樣,只不過在標記后不是對未標記的內存區域進行清理,二是讓所有的存活對象都向一端移動,然后清理掉邊界外的內存
分代算法
所謂分代就是根據對象的生命周期把內存分為幾塊,這樣就可以根據對象的“年齡”選擇合適的垃圾回收算法。在java中,把內存中的對象按生命長短分為:1.新生代:生命周期短,比如局部變量;2.老年代:生命周期長的對象;3.永久代:很少會被回收,生命周期長,比如加載的class信息。
新生代和老年代存儲在堆區,永久代存儲在方法區。大對象會直接進入老年代,比如很長的字符串或很大的數組,大對象對于JVM內存分配是個壞消息,因為大對象需要找到連續內存,否則會觸發gc,所以短命的大對象是需要盡量避免的。長期存活的對象進入老年代,對象在新生代每經歷一次minor gc,年齡加1, 默認達到15歲會進入老年代。每次Minor GC時,虛擬機會檢測每次晉升到老年代的平均大小是否大于老年代當前剩余大小,如果小于,則進行full gc。
新生代使用復制算法(因為存活的對象較少,而死亡的對象過多,如果使用標記-清除算法的話,需要遍歷標記,顯然效率較低,而使用復制算法就可以把存活的較少的對象復制到可用內存區域中,這樣效率就較高)進行GC回收,老年代因為存活率高,所以使用標記清除或者標記整理算法回收。
關于Java內存機制和GC回收機制是什么就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。