1. 程式人生 > >堆外記憶體(off-heap)、堆內記憶體(on-heap)

堆外記憶體(off-heap)、堆內記憶體(on-heap)

堆Heap是記憶體中動態分配物件存在的地方。如果使用new一個物件,它就被分配在堆記憶體上。這是相對於Stack,如果你有一個區域性變數則它是位於Stack棧記憶體空間。

一般情況下,Java中分配的非空物件都是由Java虛擬機器的垃圾收集器管理的,也稱為堆內記憶體(on-heap memory)。虛擬機器會定期對垃圾記憶體進行回收,在某些特定的時間點,它會進行一次徹底的回收(full gc)。徹底回收時,垃圾收集器會對所有分配的堆內記憶體進行完整的掃描,這意味著一個重要的事實——這樣一次垃圾收集對Java應用造成的影響,跟堆的大小是成正比的。過大的堆會影響Java應用的效能。

對於這個問題,一種解決方案就是使用堆外記憶體(off-heap memory)。堆外記憶體意味著把記憶體物件分配在Java虛擬機器的堆以外的記憶體,這些記憶體直接受作業系統管理(而不是虛擬機器)。這樣做的結果就是能保持一個較小的堆,以減少垃圾收集對應用的影響。使用堆外記憶體能夠降低GC導致的暫停。

堆外記憶體,它和記憶體池一樣,也能縮短垃圾回收時間,但是它適用的物件和記憶體池完全相反。記憶體池往往適用於生命期較短的可變物件,而生命期中等或較長的物件,正是堆外記憶體要解決的。堆外記憶體有以下特點:

  • 對於大記憶體有良好的伸縮性
  • 對垃圾回收停頓的改善可以明顯感覺到
  • 在程序間可以共享,減少虛擬機器間的複製

當然堆外記憶體也有它自己的問題,最大的問題就是你的資料結構變得不那麼直觀,如果資料結構比較複雜,就要對它進行序列化(serialization),而序列化本身也會影響效能。另一個問題是由於你可以使用更大的記憶體,你可能開始擔心虛擬記憶體(即硬碟)的速度對你的影響了。

比方說,EHCache(Terrcotta BigMemory)的 off-heap將你的物件從堆中脫離出來序列化,然後儲存在一大塊記憶體中,這就像它儲存到磁碟上上一樣,但它仍然在RAM中。物件在這種狀態下不能直接使用,它們必須首先反序列化。也不受垃圾收集。序列化和反序列化會影響效能。

應用場景:

  1. Session會話快取,儲存不啟用的使用者session,比如使用者沒有正常退出,我們也無法確定他會不會短時間內再回來,將其會話存到堆外記憶體。一旦再次登入,無需訪問資料庫可再次啟用。
  2. 計算結果的快取,大量查詢的結果等,擊中率比較低的都可以遷移到堆外。
參考: