1. 程式人生 > >堆外記憶體與NIO

堆外記憶體與NIO

堆外記憶體(off-heap),堆記憶體(on-heap)

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

對於這個問題,一種解決方案就是使用堆外記憶體(off-heap memory)。堆外記憶體意味著把記憶體物件分配在Java

虛擬機器的堆以外的記憶體,這些記憶體直接受作業系統管理(而不是虛擬機器)。這樣做的結果就是能保持一個較小的堆,以減少垃圾收集對應用的影響。

HeapByteBuffer與DirectByteBuffer,在原理上,前者可以看出分配的buffer是在heap區域的,其實真正flush到遠端的時候會先拷貝得到直接記憶體,再做下一步操作(考慮細節還會到OS級別的核心區直接記憶體),其實發送靜態檔案最快速的方法是通過OS級別的send_file,只會經過OS一個核心拷貝,而不會來回拷貝;在NIO的框架下,很多框架會採用DirectByteBuffer來操作,這樣分配的記憶體不再是在java heap上,而是在C heap上,經過效能測試,可以得到非常快速的網路互動,在大量的網路互動下,一般速度會比HeapByteBuffer要快速好幾倍。

直接記憶體(Direct Memory)並不是虛擬機器執行時資料區的一部分,也不是Java虛擬機器規範中定義的記憶體區域,但是這部分記憶體也被頻繁地使用,而且也可能導致OutOfMemoryError 異常出現,所以我們放到這裡一起講解。 
在JDK 1.4 中新加入了NIO(New Input/Output)類,引入了一種基於通道(Channel)與緩衝區(Buffer)的I/O 方式,它可以使用Native 函式庫
直接分配堆外記憶體,然後通過一個儲存在Java 堆裡面的DirectByteBuffer 物件作為這塊記憶體的引用進行操作。這樣能在一些場景中顯著提高效能,因為避免了在Java 堆和Native 堆中來回複製資料。

堆外記憶體的優點和缺點

堆外記憶體,其實就是不受JVM控制的記憶體。相比於堆內記憶體有幾個優勢: 
  1 減少了垃圾回收的工作,因為垃圾回收會暫停其他的工作(可能使用多執行緒或者時間片的方式,根本感覺不到) 
  2 加快了複製的速度。因為堆內在flush到遠端時,會先複製到直接記憶體(非堆記憶體),然後在傳送;而堆外記憶體相當於省略掉了這個工作。 
  而福之禍所依,自然也有不好的一面: 
  1 堆外記憶體難以控制,如果記憶體洩漏,那麼很難排查 
  2 堆外記憶體相對來說,不適合儲存很複雜的物件。一般簡單的物件或者扁平化的比較適合。

總結and轉自:

http://blog.csdn.net/qq_17612199/article/details/52316719

http://blog.csdn.net/u010722938/article/details/51558315