java direct buffer VS non-direct buffer

在java NIO中,有兩種不同的buffer:direct buffer和non-direct buffer。所謂direct buffer,就是指直接在底層分配的緩存(比如操作系統內核緩存),而non-direct buffer就是在java堆中分配的緩存,即heap buffer。

1、 劣勢:創建和釋放Direct Buffer的代價比Heap Buffer得要高
2、 區別:Direct Buffer不是分配在堆上的,它不被GC直接管理(但Direct Buffer的JAVA對象是歸GC管理的,只要GC回收了它的JAVA對象,操作系統纔會釋放Direct Buffer所申請的空間),它似乎給人感覺是“內核緩衝區(buffer in kernel)”。Heap Buffer則是分配在堆上的,或者我們可以簡單理解爲Heap Buffer就是byte[]數組的一種封裝形式,查看JAVA源代碼實現,Heap Buffer也的確是這樣。
3、 優勢:當我們把一個Direct Buffer寫入Channel的時候,就好比是“內核緩衝區”的內容直接寫入了Channel,這樣顯然快了,減少了數據拷貝(因爲我們平時的read/write都是需要在I/O設備與應用程序空間之間的“內核緩衝區”中轉一下的)。而當我們把一個Heap Buffer寫入Channel的時候,實際上底層實現會先構建一個臨時的Direct Buffer,然後把Heap Buffer的內容複製到這個臨時的Direct Buffer上,再把這個Direct Buffer寫出去。當然,如果我們多次調用write方法,把一個Heap Buffer寫入Channel,底層實現可以重複使用臨時的Direct Buffer,這樣不至於因爲頻繁地創建和銷燬Direct Buffer影響性能。

如果我們構造一個ByteBuffer僅僅使用一次,不復用它,那麼Direct Buffer和Heap Buffer沒有明顯的區別。兩個地方我們可能通過Direct Buffer來提高性能:
1、 大文件,儘管我們Direct Buffer只用一次,但是如果內容很大,Heap Buffer的複製代價會很高,此時用Direct Buffer能提高性能。這就是爲什麼,當我們下載一個大文件時,服務端除了用SendFile機制,也可以用“內存映射”,把大文件映射到內存,也就是MappedByteBuffer,是一種Direct Buffer,然後把這個MappedByteBuffer直接寫入SocketChannel,這樣減少了數據複製,從而提高了性能。
2、 重複使用的數據,比如HTTP的錯誤信息,例如404呀,這些信息是每次請求,響應數據都一樣的,那麼我們可以把這些固定的信息預先存放在Direct Buffer中(當然部分修改Direct Buffer中的信息也可以,重要的是Direct Buffer要能被重複使用),這樣把Direct Buffer直接寫入SocketChannel就比寫入Heap Buffer要快了。 

簡單的說,我們需要牢記三點:
(1) 平時的read/write,都會在I/O設備與應用程序空間之間經歷一個“內核緩衝區”。
(2) Direct Buffer就好比是“內核緩衝區”上的緩存,不直接受GC管理;而Heap Buffer就僅僅是byte[]字節數組的包裝形式。因此把一個Direct Buffer寫入一個Channel的速度要比把一個Heap Buffer寫入一個Channel的速度要快。
(3) Direct Buffer創建和銷燬的代價很高,所以要用在儘可能重用的地方。

發佈了75 篇原創文章 · 獲贊 6 · 訪問量 33萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章