您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關JVM的分代模型是什么,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
我們將針對jvm堆內存的分代模型做一個詳細的解析,和大家一起輕松理解jvm的分代模型。
相信看過其他文章的小伙伴們可能都知道,jvm的分代模型包括:年輕代、老年代、永久代。
那么它們分別代表著什么角色呢?我們先來看一段代碼
public class Main { public static void main(String[] args) { while (true){ load(); } } public static void load(){ SysUser sysUser = new SysUser(); sysUser.setAvatar("1"); } }
這段代碼本身沒有什么特殊的含義,主要是理解jvm的運行機制。
首先一旦執行main()方法,就會把main()方法的棧幀壓入main線程的虛擬機棧,然后調用load()方法后,又會把load()方法的棧幀壓入虛擬機棧。
接著在執行load()方法時,會在java堆內存中創建一個SysUser對象實例,而棧幀中會有sysUser局部變量引用堆內存中的SysUser對象實例。
如下圖:
到這里上篇文章都講解過,相信大家都能看懂。
變量的存活時間
現在我們思考一下會發現,這個SysUser對象實際上屬于一個短暫存活的對象,因為在load()方法執行完畢后,load()方法的棧幀就會出棧。
而一旦出棧,就沒有了sysUser這個局部變量來引用SysUser這個對象的實例。
所以,其實這個SysUser對象已經沒有用了,但是它還在占用著堆內存的空間,那么對于這種沒有引用的對象實例jvm是如何處理的呢?
這就要說到jvm的垃圾回收機制了,jvm本身是有垃圾回收機制的,它是一個后臺線程,會把沒有人引用的SysUser對象實例給回收掉,不斷的釋放內存空間。
所以這個SysUser對象實例是一個存活時間很短的對象,可能在執行load()方法的時候被創建出來,執行之后就被垃圾回收掉了。
而這種對象在我們平時的開發中是很常見的,占絕大多數比例。
現在我們將上邊的代碼改造一下:
public class Main { private static SysUser sysUser = new SysUser(); public static void main(String[] args) { while (true){ load(); } } public static void load(){ sysUser.setAvatar("1"); } }
其實就是把局部變量sysUser變成了靜態變量,這樣修改后,sysUser不在作為局部變量保存在棧中,而是和class類文件一起保存在方法區中,這樣SysUser對象實例就會一直被這個靜態變量引用,所以不會被垃圾回收,一直保存在堆內存中。如下圖:
分代模型
接下來我們進入核心內容,就是jvm的分代模型了。
上文中我們發現,根據我們的編碼方式的不同,采用不同的方式創建和使用對象,對象的存活時間是不同的。
所以jvm將內存區分為兩個區域:年輕代和老年代。
年輕代就是我們的第一種局部變量的示例,創建和使用完畢后會被垃圾回收掉。
老年代就是第二種靜態變量的示例,創建后需要長期在堆內存中存活。
相信到這里大家就應該理解了什么樣的對象是短期存活的對象,什么樣的對象是長期存活的對象,那么它們是如何分別存在年輕代和老年代中的呢?為什么要這么區分呢?
其實這與垃圾回收機制是密不可分的。
對于年輕代里的對象,他們的特點是創建后很快就會被回收,而對于老年代里的對象,他們的特點是需要長期存活,所以這兩種對象是不能用一種垃圾回收算法進行回收的,所以需要區分成兩個。
對于長期存在的靜態變量sysUser,其實剛開始的時候也是在年輕代的,那它是什么時候進入老年代的呢?我們下文會講解這個問題。
那永久代又是什么呢?其實永久代就是我們說的jvm的方法區,用于存放一下類信息的,這部分之后的文章涉及到會詳解,現在理解到這就可以了。
新生代的垃圾回收
前文我們了解了,當load方法執行完畢出棧后,里面的局部變量sysUser就沒了,堆內存中的SysUser對象就沒有引用了,所以會被垃圾回收掉。
那么問題來了,是沒有引用后就會立即發生垃圾回收,回收掉沒有被引用的對象實例嗎?
其實不是這樣的,垃圾回收是有觸發條件的。
有一個比較常見的場景是這樣的,假設我們的代碼中創建了大量的對象,導致堆內存中囤積了大量的對象,然后這些對象現在都沒有人引用了。
這個時候,如果新生代預先分配的內存空間被占滿了,那么我們的代碼此時要新創建一個對象的時候,發現新生代空間滿了,怎么辦?
這個時候就會觸發一次新生代的垃圾回收,也稱為“Minor GC”或"Young GC",它會嘗試把新生代中沒有人引用的對象給回收掉,釋放空間。
下圖表達了這一過程:
長期存活的對象什么時候進入老年代
接下來我們談論一個話題,靜態變量引用的長期存活的對象是什么時候進入老年代的。
上文我們了解到,新生代的對象會經歷一次次的垃圾回收,而被靜態變量引用的對象因為一直被引用,所以一直不會被回收,所以此時jvm就有了一條規定。
如果新生代中的對象,在經歷了15次垃圾回收后,依然堅挺的存活著,那就證明它是個"老年人"了,然后它會被轉移到老年代中。
老年代就是存放這些年齡比較大的對象的。
那么老年代中的對象會被垃圾回收嗎?
答案是肯定的,因為老年代里的對象隨著代碼的運行,也是可以不再被任何人引用的,就需要垃圾回收了。
或者說,隨著越來越多的對象進入老年代,老年代的內存也會被占滿,所以一定是要對老年代進行垃圾回收的。
我們暫時不用考慮具體是怎么回收的,這個內容在之后的文章中我們會有詳細的解析。
上述就是小編為大家分享的JVM的分代模型是什么了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。