更新時間:2020-04-17 14:56:42 來源:動力節點 瀏覽2568次
java內存區域和內存溢出
HotSpotVM是SunJDK和OpenJDK中所帶的虛擬機,也是目前使用范圍最廣的java虛擬機。
如果一段java方法被調用次數達到一定程度,就會被判定為熱代碼交給JIT編譯器即時編譯為本地代碼,提供運行速度,這就是HotSpot虛擬機名稱的由來。
一、內存區域構成
1、程序計數器
線程私有的內存。
在虛擬機的概念模型里,字節碼解釋器工作時就是通過改變這個計數器的值來選取下一條需要執行的字節碼指令,分支、循環、異常處理、線程恢復都需要依賴這個計數器來完成。
為了線程切換后能恢復到正確的執行位置,每條線程都需要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲。
消耗內存很少,可以忽略。
2、java虛擬機棧
線程私有的內存,生命周期和線程相同。常有人把內存分為堆和棧,這個棧就是虛擬機棧,或者虛擬機棧中的局部變量表部分。
局部變量表存放了各種基本數據類型、對象引用和returnAddress(字節碼指令的地址)
3、本地方法棧
與虛擬機棧作用相似。區別是本地方法棧為虛擬機執行java方法服務,而本地方法棧則為虛擬機使用到的Native方法服務,即由非java語言實現的方法。
4、java堆
所有線程共享,虛擬機啟動時創建。
堆是java虛擬機所管理的內存中最大的一塊。唯一目的是存放對象實例,幾乎所有對象實例都在這里分配。
如果堆中沒有內存來完成實例分配,且不可擴展將會拋出OutOfMemoryError。
通過-Xmx和-Xms控制堆內存最大值最小值
5、方法區
線程共享的內存區域,用于存儲已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯后的代碼等數據。很多人習慣把Hotspot虛擬機中的方法區成為永久代,因為
GC很少出現在這個區域。方法區無法滿足內存分配需求時會跑出OutOfMemoryError。
使用動態代理或CGLib這類字節碼技術時,需要消耗很大的方法區來保證動態生成的Class能加載入內存。
通過MaxPermSize控制方法區容量
6、運行時常量池
運行時常量池是方法區的一部分
二、內存溢出
Hotspot虛擬機中,對象在內存中存儲的布局可以分為3塊區域:對象頭(Header)、實例數據(InstanceData)和對齊填充(Padding)
1、堆溢出
java.lang.OutOfMemoryError:javaheapspace
2、虛擬機棧和本地方法棧溢出
java.lang.StackOverflowError
1
3、方法區和運行時常量池溢出
java.lang.OutOfMemoryError:PermGenspace
1
垃圾收集算法和內存分配策略
主要是為了解決兩個問題:內存分配與內存回收
一、垃圾收集算法
1、標記-清除算法
首先標記出需要回收的對象,標記完成后統一回收。標記清除效率較低,而且會產生大量不連續的內存碎片。
2、復制算法
現在的商業虛擬機都采用這種收集算法來回收新生代。將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。
當回收時將Eden和Survior中還存活的對象一次性的復制到另一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。
Hotspot虛擬機默認Eden和Survivor大小比例是8:1,也就是說每次新生代中可用的內存空間為整個新生代容量的90%,只有10%的內存會被浪費。
如果Survivor空間不夠用時,需要依賴老年代進行分配擔保。
內存的分配擔保就好像我們去銀行貸款,如果信譽良好,銀行會默認我們會如期還款,只需要有一個擔保人保證如果不能還,可以從他賬戶里扣錢,這樣對銀行就沒有風險了。
如果另外一塊Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對象,這些對象直接通過分配擔保機制進入老年代。
3、標記-整理算法
復制算法在對象存活率較高時要進行較多的復制操作,效率會降低。老年代采用這種算法,與標記清除不同的時,不是直接堆可回收的對象進行清理,而是讓所有存活的對象
向一端移動,然后直接清理掉邊界以外的內存。
4、分代收集算法
一般把java堆分為新生代和老年代,新生代中每次垃圾收集都發現有大批對象死去,只有少量存活,那就選用復制算法,老年代因為對象存活率高,沒有額外空間對他進行
內存擔保,必須使用標記-清理或標記-整理算法
二、內存分配與回收策略
1、對象優先在Eden分配
-XX:+PrintGCDetails告訴虛擬機在發生垃圾收集行為時打印內存回收日志,并且在進程退出時輸出當前的內存各區域分配情況。
上面的設置可以限制java堆大小為20M不可擴展,其中新生代老年代大小分別為10M
2、大對象直接進入老年代
經常出現大對象容易導致內存還有不少空間時就提前觸發GC以獲取足夠多的連續空間來安置它們,寫程序時要盡量避免,更要避免短命大對象。
虛擬機提供一個-XX:PretenureThreshold參數,上面的配置大于3M的對象直接在老年代分配,這樣做的目的是避免在Eden區和兩個Survivor區之間發生大量的內存復制。
根據內存擔保,Survivor區無法容納的對象會直接進入到老年代。
3、長期存活的對象將進入老年代
對象在Survivor區每熬過一次GC年齡就增加一歲,當增加到一定程度(默認是15歲),就會晉升到老年代中。老年代做擔保時需要老年代有足夠多的空間,通過觸發FullGC來收集。
虛擬機性能監控命令與可視化工具
命令行
jps虛擬機進程狀況工具
jstat用于監視虛擬機各種運行狀態信息的命令行工具
jstack用于生成虛擬機當前時刻的線程快照,目的是定位線程長時間卡頓的原因
可視化工具
JConsole
以上就是動力節點java培訓機構的小編針對“Java基礎學習:java虛擬機內存管理”的內容進行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業老師隨時為你服務。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習