深入JVM虛擬機之什麼是堆外內存?什麼情況下發生堆外內存溢出或泄露?

堆內內存:

1.一般情況下,一個新的對象創建在JVM內的堆上,併爲其分配內存空間堆空間由JVM垃圾回收器管理,稱爲堆內內存(on-heap memory

2.虛擬機會定期對垃圾內存進行回收,有時會進行一次徹底的回收Full GC

3.徹底回收時,垃圾收集器會對所有分配的堆內內存進行完整的掃描,這意味一次垃圾收集對Java 應用造成的影響,跟堆的大小是成正比的,過大的堆會影響 Java 應用的性能

堆外內存:

1.和堆內內存相對應,堆外內存就是把內存對象分配在Java虛擬機的堆以外的內存,這些內存直接受操作系統管理,而不是虛擬機

2.這樣能夠維護一個較小的堆,在一定程度上減少垃圾回收對應用程序造成的影響,堆外內存也被稱爲直接內存

3.可以使用NIO包下的DirectByteBuffer進行堆外內存的管理和使用,它會在對象創建的時候就分配堆外內存

                    

堆外內存的優點:

1、保持了一個較小的堆內內存,可以減少垃圾收集對應喲的影響。

2、在使用緩存時,需要消耗一些內存空間來提升速度,使用堆內內存會給虛擬機帶來GC壓力,使用硬盤或者分佈式緩存的響應時間會比較長,這時候堆外緩存會是一個比較好的選擇。

3、堆內內存由JVM 管理,屬於用戶態,而堆外內存由操作系統管理,屬於內核態。如果從堆內向磁盤些數據時,數據會被先複製到堆外內存,即內核緩衝區,然後再由操作系統寫入磁盤。使用堆外內存,直接寫入磁盤,提升了效率。

 

 

堆外內存的缺點:

1、堆外內存的缺點就是內存難以控制。

2、使用堆外內存就間接失去了使用JVM管理內存的可能性,一旦發生內存溢出時排查起來非常困難。

堆外內存泄露:

1.操作系統對每個進程能管理的內存都是有限制的,對於32位系統而言,Linux最大接近4GWindows大概2G,如果堆內實際內存1.6G,那留給堆外內存的大小也就0.4G
 
2.堆外內存不會像新生代和老年代那樣,發現空間不足就通知收集器進行回收
 
3.它只能等待老年代滿了後觸發Full GC,然後JVM順便地清理堆外內存中廢棄的對象
 
4.在極端情況下如果JVM一直沒有執行Full GC的話, 堆外內存也一直得不到釋放
 
 

堆外內存泄露的干預方法:

1.需要一種機制能夠主動對它進行清理需要顯示的調用System.gc()
 
2.但假如打開了 -XX:+DisableExplicitGC 開關,禁止顯示調用System.gc()
 
3.假如堆外內存空間已經滿了雖然肯堆中還有很多空閒的內存,堆外內存也不得不拋出內存溢出異常
 
 

堆外內存回收過程:

1.JVM在堆內只保存堆外內存的引用,用DirectByteBuffer對象來表示
 
2.每個DirectByteBuffer對象在初始化時,都會創建一個對應的Cleaner對象
 
3.DirectByteBuffer對象在某次GC中被回收,只有Cleaner對象知道堆外內存的地址
 
4.當下一次GC執行時,Cleaner對象會觸發自身clean方法清理對應的堆外內存
 
5.Cleaner對象在下次GC時被回收

總結:

1.堆外內存有良好的伸縮性對垃圾回收停頓的改善可以明顯感覺到提高了IO效率
 
2.堆外內存的使用需要我們重點關注,當發生內存溢出時排查起來非常困難

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章