JVM 堆 棧 方法區(qū)

JVM:Java Virtual Machine

一、堆 棧 方法區(qū)分布


1、堆區(qū):

提供所有類實例和數(shù)組對象存儲區(qū)域

jvm只有一個堆區(qū)(heap)被所有線程共享,堆中不存放基本類型和對象引用,只存放對象本身

2、棧區(qū):

棧由棧幀組成,

每個線程run時都會分配自己的棧內(nèi)存空間,每個方法運行時會在自己的棧內(nèi)存中分配棧幀內(nèi)存區(qū),各方法的局部變量存儲于各自的棧幀內(nèi)存區(qū)

每個線程包含一個棧區(qū),棧中只保存基礎數(shù)據(jù)類型的對象和自定義對象的引用(不是對象),對象都存放在堆區(qū)中

每個棧中的數(shù)據(jù)(原始類型和對象引用)都是私有的,其他棧不能訪問。

3、方法區(qū):

又叫靜態(tài)區(qū),跟堆一樣,被所有的線程共享。方法區(qū)包含所有的class和static變量。

運行時常量池都分配在 Java 虛擬機的方法區(qū)之中

4、本地方法棧

本地方法:簡單地講,一個Native Method就是一個java調(diào)用非java代碼的接口。一個Native Method是這樣一個java的方法:該方法的實現(xiàn)由非java語言實現(xiàn),比如C。這個特征并非java所特有,很多其它的編程語言都有這一機制,比如在C++中,你可以用extern "C"告知C++編譯器去調(diào)用一個C的函數(shù)。

本地方法棧(Native Method Stacks)與 Java 虛擬機棧所發(fā)揮的作用是非常相似的,其區(qū)別不過是虛擬機棧為虛擬機執(zhí)行 Java 方法(也就是字節(jié)碼)服務,而本地方法棧則是為虛擬機使用到的 Native 方法服務。

如:

二、Java中直接使用==操作符,比較的是兩個字符串的引用地址,并不是比較內(nèi)容,比較內(nèi)容請用String.equals()。

三、堆

JVM


年輕代默認占1/3 老年代默認占2/3? Eden默認8/10 s0默認1/10 s1默認 1/10

new Data()先進入Eden 經(jīng)過minor GC計算后放入 s0(from), 再進行minor GC放入s1(to) 再放入s0 直到對象年齡達到15,若還是有引用對象,再放入老年代

1.年輕代?

年輕代用來存放新近創(chuàng)建的對象,尺寸隨堆大小的增大和減小而相應的變化,默認值是保持為堆大小的1/15,可以通過 -Xmn 參數(shù)設置年輕代為固定大小,也可以通過 -XX:NewRatio 來設置年輕代與年老代的大小比例,年青代的特點是對象更新速度快,在短時間內(nèi)產(chǎn)生大量的“死亡對象”。

年輕代的特點是產(chǎn)生大量的死亡對象,并且要是產(chǎn)生連續(xù)可用的空間, 所以使用復制清除算法和并行收集器進行垃圾回收.對年輕代的垃圾回收稱作初級回收 (minor gc)。

初級回收將年輕代分為三個區(qū)域, 一個新生代 , 2個大小相同的復活代, 應用程序只能使用一個新生代和一個復活代, 當發(fā)生初級垃圾回收的時候,gc掛起程序, 然后將新生代和復活代中的存活對象復制到另外一個非活動的復活代中,然后一次性清除新生代和復活代,將原來的非復活代標記成為活動復活代。將在指定次數(shù)回收后仍然存在的對象移動到老年代中,初級回收后,得到一個空的可用的新生代。

新生代幾乎是所有 Java 對象出生的地方,即 Java 對象申請的內(nèi)存以及存放都是在這個地方。Java 中的大部分對象通常不需長久存活,具有朝生夕滅的性質(zhì)。 當一個對象被判定為 “死亡” 的時候,GC 就有責任來回收掉這部分對象的內(nèi)存空間。新生代是 GC 收集垃圾的頻繁區(qū)域。 當對象在 Eden 出生后,在經(jīng)過一次 Minor GC 后,如果對象還存活,并且能夠被另外一塊 Survivor 區(qū)域所容納,則使用復制算法將這些仍然還存活的對象復制到另外一塊 Survivor 區(qū)域中,然后清理所使用過的 Eden 以及 Survivor 區(qū)域,并且將這些對象的年齡設置為1,以后對象在 Survivor 區(qū)每熬過一次 Minor GC,就將對象的年齡 + 1,當對象的年齡達到某個值時 ( 默認是 15 歲,可以通過參數(shù) -XX:MaxTenuringThreshold 來設定 ),這些對象就會成為老年代。 但這也不是一定的,對于一些較大的對象 ( 即需要分配一塊較大的連續(xù)內(nèi)存空間 ) 則是直接進入到老年代。

2.老年代?

Full GC 是發(fā)生在老年代的垃圾收集動作,所采用的是標記-清除算法。

現(xiàn)實的生活中,老年代的人通常會比新生代的人 “早死”。堆內(nèi)存中的老年代(Old)不同于這個,老年代里面的對象幾乎個個都是在 Survivor 區(qū)域中熬過來的,它們是不會那么容易就 “死掉” 了的。因此,F(xiàn)ull GC 發(fā)生的次數(shù)不會有 Minor GC 那么頻繁,并且做一次 Full GC 要比進行一次 Minor GC 的時間更長。 另外,標記-清除算法收集垃圾的時候會產(chǎn)生許多的內(nèi)存碎片 ( 即不連續(xù)的內(nèi)存空間 ),此后需要為較大的對象分配內(nèi)存空間時,若無法找到足夠的連續(xù)的內(nèi)存空間,就會提前觸發(fā)一次 GC 的收集動作。

3.永久代?

永久代是Hotspot虛擬機特有的概念,是方法區(qū)的一種實現(xiàn),別的JVM都沒有這個東西。在Java 8中,永久代被徹底移除,取而代之的是另一塊與堆不相連的本地內(nèi)存——元空間。?

永久代或者“Perm Gen”包含了JVM需要的應用元數(shù)據(jù),這些元數(shù)據(jù)描述了在應用里使用的類和方法。注意,永久代不是Java堆內(nèi)存的一部分。永久代存放JVM運行時使用的類。永久代同樣包含了Java SE庫的類和方法。永久代的對象在full GC時進行垃圾收集。

? ? Jvm區(qū)域總體分兩類,heap區(qū)和非heap區(qū)。heap區(qū)又分:Eden Space(伊甸園)、Survivor Space(幸存者區(qū))、Tenured Gen(老年代-養(yǎng)老區(qū))。 非heap區(qū)又分:Code Cache(代碼緩存區(qū))、Perm Gen(永久代)、Jvm Stack(java虛擬機棧)、Local Method Statck(本地方法棧)。

??? HotSpot虛擬機GC算法采用分代收集算法:

1、一個人(對象)出來(new 出來)后會在Eden Space(伊甸園)無憂無慮的生活,直到GC到來打破了他們平靜的生活。GC會逐一問清楚每個對象的情況,有沒有錢(此對象的引用)啊,因為GC想賺錢呀,有錢的才可以敲詐嘛。然后富人就會進入Survivor Space(幸存者區(qū)),窮人的就直接kill掉。

2、并不是進入Survivor Space(幸存者區(qū))后就保證人身是安全的,但至少可以活段時間。GC會定期(可以自定義)會對這些人進行敲詐,億萬富翁每次都給錢,GC很滿意,就讓其進入了Genured Gen(養(yǎng)老區(qū))。萬元戶經(jīng)不住幾次敲詐就沒錢了,GC看沒有啥價值啦,就直接kill掉了。

3、進入到養(yǎng)老區(qū)的人基本就可以保證人身安全啦,但是億萬富豪有的也會揮霍成窮光蛋,只要錢沒了,GC還是kill掉。

分區(qū)的目的:新生區(qū)由于對象產(chǎn)生的比較多并且大都是朝生夕滅的,所以直接采用標記-清理算法。而養(yǎng)老區(qū)生命力很強,則采用復制算法,針對不同情況使用不同算法。

非heap區(qū)域中Perm Gen中放著類、方法的定義,jvm Stack區(qū)域放著方法參數(shù)、局域變量等的引用,方法執(zhí)行順序按照棧的先入后出方式。

GC工作機制

SUN的jvm內(nèi)存池被劃分為以下幾個部分:

Eden?Space (heap)

內(nèi)存最初從這個線程池分配給大部分對象。

Survivor Space (heap)

用于保存在eden space內(nèi)存池中經(jīng)過垃圾回收后沒有被回收的對象。

Tenured Generation (heap)

用于保持已經(jīng)在survivor space內(nèi)存池中存在了一段時間的對象。

Permanent Generation (non-heap)

保存虛擬機自己的靜態(tài)(reflective)數(shù)據(jù),例如類(class)和方法(method)對象。Java虛擬機共享這些類數(shù)據(jù)。這個區(qū)域被分割為只讀的和只寫的。

Code Cache (non-heap)

HotSpot Java虛擬機包括一個用于編譯和保存本地代碼(native code)的內(nèi)存,叫做“代碼緩存區(qū)”(code cache)。

簡單來講,jvm的內(nèi)存回收過程是這樣的:

對象在Eden Space創(chuàng)建,當Eden Space滿了的時候,gc就把所有在Eden Space中的對象掃描一次,把所有有效的對象復制到第一個Survivor Space,同時把無效的對象所占用的空間釋放。當Eden Space再次變滿了的時候,就啟動移動程序把Eden Space中有效的對象復制到第二個Survivor Space,同時,也將第一個Survivor Space中的有效對象復制到第二個Survivor Space。如果填充到第二個Survivor Space中的有效對象被第一個Survivor Space或Eden Space中的對象引用,那么這些對象就是長期存在的,此時這些對象將被復制到Permanent Generation。

若垃圾收集器依據(jù)這種小幅度的調(diào)整收集不能騰出足夠的空間,就會運行Full GC,此時jvm gc停止所有在堆中運行的線程并執(zhí)行清除動作。

參考:https://blog.csdn.net/qq_39375778/article/details/93133442

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • GC區(qū)域Eden Survivor(from,to), Old Gen和Perm Gen VM區(qū)域總體分兩類,he...
    Fitz_Lee閱讀 500評論 0 0
  • 轉(zhuǎn)載blog.csdn.net/ning109314/article/details/10411495/ JVM工...
    forever_smile閱讀 5,518評論 1 56
  • http://www.cnblogs.com/angeldevil/p/3801189.html值得一看 Clas...
    snail_knight閱讀 1,621評論 1 0
  • JVM架構 當一個程序啟動之前,它的class會被類裝載器裝入方法區(qū)(Permanent區(qū)),執(zhí)行引擎讀取方法區(qū)的...
    cocohaifang閱讀 1,853評論 0 7
  • 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別 內(nèi)存溢出:out of memory,是指程序在申請內(nèi)存時,沒有足夠的內(nèi)存空間供其使用,...
    Aimerwhy閱讀 808評論 0 1

友情鏈接更多精彩內(nèi)容