JVM:Java Virtual Machine
一、堆 棧 方法區(qū)分布
1、堆區(qū):
提供所有類實(shí)例和數(shù)組對象存儲區(qū)域
jvm只有一個(gè)堆區(qū)(heap)被所有線程共享侵状,堆中不存放基本類型和對象引用胁后,只存放對象本身
2讯泣、棧區(qū):
棧由棧幀組成衅枫,
每個(gè)線程run時(shí)都會分配自己的棧內(nèi)存空間恐仑,每個(gè)方法運(yùn)行時(shí)會在自己的棧內(nèi)存中分配棧幀內(nèi)存區(qū),各方法的局部變量存儲于各自的棧幀內(nèi)存區(qū)
每個(gè)線程包含一個(gè)棧區(qū)为鳄,棧中只保存基礎(chǔ)數(shù)據(jù)類型的對象和自定義對象的引用(不是對象),對象都存放在堆區(qū)中
每個(gè)棧中的數(shù)據(jù)(原始類型和對象引用)都是私有的腕让,其他棧不能訪問孤钦。
3、方法區(qū):
又叫靜態(tài)區(qū)纯丸,跟堆一樣偏形,被所有的線程共享。方法區(qū)包含所有的class和static變量觉鼻。
運(yùn)行時(shí)常量池都分配在 Java 虛擬機(jī)的方法區(qū)之中
4俊扭、本地方法棧
本地方法:簡單地講,一個(gè)Native Method就是一個(gè)java調(diào)用非java代碼的接口坠陈。一個(gè)Native Method是這樣一個(gè)java的方法:該方法的實(shí)現(xiàn)由非java語言實(shí)現(xiàn)萨惑,比如C。這個(gè)特征并非java所特有仇矾,很多其它的編程語言都有這一機(jī)制庸蔼,比如在C++中,你可以用extern "C"告知C++編譯器去調(diào)用一個(gè)C的函數(shù)贮匕。
本地方法棧(Native Method Stacks)與 Java 虛擬機(jī)棧所發(fā)揮的作用是非常相似的姐仅,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行 Java 方法(也就是字節(jié)碼)服務(wù),而本地方法棧則是為虛擬機(jī)使用到的 Native 方法服務(wù)。
如:
二掏膏、Java中直接使用==操作符劳翰,比較的是兩個(gè)字符串的引用地址,并不是比較內(nèi)容馒疹,比較內(nèi)容請用String.equals()佳簸。
三、堆
年輕代默認(rèn)占1/3 老年代默認(rèn)占2/3? Eden默認(rèn)8/10 s0默認(rèn)1/10 s1默認(rèn) 1/10
new Data()先進(jìn)入Eden 經(jīng)過minor GC計(jì)算后放入 s0(from), 再進(jìn)行minor GC放入s1(to) 再放入s0 直到對象年齡達(dá)到15行冰,若還是有引用對象溺蕉,再放入老年代
1.年輕代?
年輕代用來存放新近創(chuàng)建的對象,尺寸隨堆大小的增大和減小而相應(yīng)的變化悼做,默認(rèn)值是保持為堆大小的1/15疯特,可以通過 -Xmn 參數(shù)設(shè)置年輕代為固定大小,也可以通過 -XX:NewRatio 來設(shè)置年輕代與年老代的大小比例肛走,年青代的特點(diǎn)是對象更新速度快漓雅,在短時(shí)間內(nèi)產(chǎn)生大量的“死亡對象”。
年輕代的特點(diǎn)是產(chǎn)生大量的死亡對象,并且要是產(chǎn)生連續(xù)可用的空間, 所以使用復(fù)制清除算法和并行收集器進(jìn)行垃圾回收.對年輕代的垃圾回收稱作初級回收 (minor gc)朽色。
初級回收將年輕代分為三個(gè)區(qū)域, 一個(gè)新生代 , 2個(gè)大小相同的復(fù)活代, 應(yīng)用程序只能使用一個(gè)新生代和一個(gè)復(fù)活代, 當(dāng)發(fā)生初級垃圾回收的時(shí)候,gc掛起程序, 然后將新生代和復(fù)活代中的存活對象復(fù)制到另外一個(gè)非活動的復(fù)活代中,然后一次性清除新生代和復(fù)活代邻吞,將原來的非復(fù)活代標(biāo)記成為活動復(fù)活代。將在指定次數(shù)回收后仍然存在的對象移動到老年代中葫男,初級回收后抱冷,得到一個(gè)空的可用的新生代。
新生代幾乎是所有 Java 對象出生的地方梢褐,即 Java 對象申請的內(nèi)存以及存放都是在這個(gè)地方旺遮。Java 中的大部分對象通常不需長久存活,具有朝生夕滅的性質(zhì)盈咳。 當(dāng)一個(gè)對象被判定為 “死亡” 的時(shí)候耿眉,GC 就有責(zé)任來回收掉這部分對象的內(nèi)存空間。新生代是 GC 收集垃圾的頻繁區(qū)域鱼响。 當(dāng)對象在 Eden 出生后鸣剪,在經(jīng)過一次 Minor GC 后,如果對象還存活丈积,并且能夠被另外一塊 Survivor 區(qū)域所容納筐骇,則使用復(fù)制算法將這些仍然還存活的對象復(fù)制到另外一塊 Survivor 區(qū)域中,然后清理所使用過的 Eden 以及 Survivor 區(qū)域桶癣,并且將這些對象的年齡設(shè)置為1拥褂,以后對象在 Survivor 區(qū)每熬過一次 Minor GC,就將對象的年齡 + 1牙寞,當(dāng)對象的年齡達(dá)到某個(gè)值時(shí) ( 默認(rèn)是 15 歲饺鹃,可以通過參數(shù) -XX:MaxTenuringThreshold 來設(shè)定 )莫秆,這些對象就會成為老年代。 但這也不是一定的悔详,對于一些較大的對象 ( 即需要分配一塊較大的連續(xù)內(nèi)存空間 ) 則是直接進(jìn)入到老年代镊屎。
2.老年代?
Full GC 是發(fā)生在老年代的垃圾收集動作,所采用的是標(biāo)記-清除算法茄螃。
現(xiàn)實(shí)的生活中缝驳,老年代的人通常會比新生代的人 “早死”。堆內(nèi)存中的老年代(Old)不同于這個(gè)归苍,老年代里面的對象幾乎個(gè)個(gè)都是在 Survivor 區(qū)域中熬過來的用狱,它們是不會那么容易就 “死掉” 了的。因此拼弃,F(xiàn)ull GC 發(fā)生的次數(shù)不會有 Minor GC 那么頻繁夏伊,并且做一次 Full GC 要比進(jìn)行一次 Minor GC 的時(shí)間更長。 另外吻氧,標(biāo)記-清除算法收集垃圾的時(shí)候會產(chǎn)生許多的內(nèi)存碎片 ( 即不連續(xù)的內(nèi)存空間 )溺忧,此后需要為較大的對象分配內(nèi)存空間時(shí),若無法找到足夠的連續(xù)的內(nèi)存空間盯孙,就會提前觸發(fā)一次 GC 的收集動作鲁森。
3.永久代?
永久代是Hotspot虛擬機(jī)特有的概念,是方法區(qū)的一種實(shí)現(xiàn)振惰,別的JVM都沒有這個(gè)東西歌溉。在Java 8中,永久代被徹底移除骑晶,取而代之的是另一塊與堆不相連的本地內(nèi)存——元空間研底。?
永久代或者“Perm Gen”包含了JVM需要的應(yīng)用元數(shù)據(jù),這些元數(shù)據(jù)描述了在應(yīng)用里使用的類和方法透罢。注意,永久代不是Java堆內(nèi)存的一部分冠蒋。永久代存放JVM運(yùn)行時(shí)使用的類羽圃。永久代同樣包含了Java SE庫的類和方法。永久代的對象在full GC時(shí)進(jìn)行垃圾收集抖剿。
? ? 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虛擬機(jī)棧)甥温、Local Method Statck(本地方法棧)。
??? HotSpot虛擬機(jī)GC算法采用分代收集算法:
1妓布、一個(gè)人(對象)出來(new 出來)后會在Eden Space(伊甸園)無憂無慮的生活姻蚓,直到GC到來打破了他們平靜的生活。GC會逐一問清楚每個(gè)對象的情況匣沼,有沒有錢(此對象的引用)啊狰挡,因?yàn)镚C想賺錢呀,有錢的才可以敲詐嘛释涛。然后富人就會進(jìn)入Survivor Space(幸存者區(qū))加叁,窮人的就直接kill掉。
2唇撬、并不是進(jìn)入Survivor Space(幸存者區(qū))后就保證人身是安全的它匕,但至少可以活段時(shí)間。GC會定期(可以自定義)會對這些人進(jìn)行敲詐局荚,億萬富翁每次都給錢超凳,GC很滿意,就讓其進(jìn)入了Genured Gen(養(yǎng)老區(qū))耀态。萬元戶經(jīng)不住幾次敲詐就沒錢了轮傍,GC看沒有啥價(jià)值啦,就直接kill掉了首装。
3创夜、進(jìn)入到養(yǎng)老區(qū)的人基本就可以保證人身安全啦,但是億萬富豪有的也會揮霍成窮光蛋仙逻,只要錢沒了驰吓,GC還是kill掉。
分區(qū)的目的:新生區(qū)由于對象產(chǎn)生的比較多并且大都是朝生夕滅的系奉,所以直接采用標(biāo)記-清理算法檬贰。而養(yǎng)老區(qū)生命力很強(qiáng),則采用復(fù)制算法缺亮,針對不同情況使用不同算法翁涤。
非heap區(qū)域中Perm Gen中放著類、方法的定義萌踱,jvm Stack區(qū)域放著方法參數(shù)葵礼、局域變量等的引用,方法執(zhí)行順序按照棧的先入后出方式并鸵。
GC工作機(jī)制
SUN的jvm內(nèi)存池被劃分為以下幾個(gè)部分:
Eden?Space (heap)
內(nèi)存最初從這個(gè)線程池分配給大部分對象鸳粉。
Survivor Space (heap)
用于保存在eden space內(nèi)存池中經(jīng)過垃圾回收后沒有被回收的對象。
Tenured Generation (heap)
用于保持已經(jīng)在survivor space內(nèi)存池中存在了一段時(shí)間的對象园担。
Permanent Generation (non-heap)
保存虛擬機(jī)自己的靜態(tài)(reflective)數(shù)據(jù)届谈,例如類(class)和方法(method)對象枯夜。Java虛擬機(jī)共享這些類數(shù)據(jù)。這個(gè)區(qū)域被分割為只讀的和只寫的疼约。
Code Cache (non-heap)
HotSpot Java虛擬機(jī)包括一個(gè)用于編譯和保存本地代碼(native code)的內(nèi)存卤档,叫做“代碼緩存區(qū)”(code cache)。
簡單來講程剥,jvm的內(nèi)存回收過程是這樣的:
對象在Eden Space創(chuàng)建劝枣,當(dāng)Eden Space滿了的時(shí)候,gc就把所有在Eden Space中的對象掃描一次织鲸,把所有有效的對象復(fù)制到第一個(gè)Survivor Space舔腾,同時(shí)把無效的對象所占用的空間釋放。當(dāng)Eden Space再次變滿了的時(shí)候搂擦,就啟動移動程序把Eden Space中有效的對象復(fù)制到第二個(gè)Survivor Space稳诚,同時(shí),也將第一個(gè)Survivor Space中的有效對象復(fù)制到第二個(gè)Survivor Space瀑踢。如果填充到第二個(gè)Survivor Space中的有效對象被第一個(gè)Survivor Space或Eden Space中的對象引用扳还,那么這些對象就是長期存在的,此時(shí)這些對象將被復(fù)制到Permanent Generation橱夭。
若垃圾收集器依據(jù)這種小幅度的調(diào)整收集不能騰出足夠的空間氨距,就會運(yùn)行Full GC,此時(shí)jvm gc停止所有在堆中運(yùn)行的線程并執(zhí)行清除動作棘劣。
參考:https://blog.csdn.net/qq_39375778/article/details/93133442