成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

作為 Java 開發者,你需要了解的堆外內存知識

存儲 存儲軟件
很久沒有遇到堆外內存相關的問題了,五一假期剛結束,便不期而遇,以前也處理過幾次這類問題,但都沒有總結,覺得是時候總結一下了。

 1. 引言

很久沒有遇到堆外內存相關的問題了,五一假期剛結束,便不期而遇,以前也處理過幾次這類問題,但都沒有總結,覺得是時候總結一下了。

先來看一個 Demo:在 Demo 中分配堆外內存用的是 allocateDirect 方法,但其內部調用的是 DirectByteBuffer,換言之,DirectByteBuffer 才是實際操作堆外內存的類,因此,本場 Chat 將圍繞 DirectByteBuffer 展開。

[[233033]]

  1. import java.nio.ByteBuffer;public class Demo {    public static void main( String[] args ) 
  2.     {        //分配一塊1024Bytes的堆外內存(直接內存) 
  3.         //allocateDirect方法內部調用的是DirectByteBuffer 
  4.         ByteBuffer buffer=ByteBuffer.allocateDirect(1024); 
  5.         System.out.println(buffer.capacity());        //向堆外內存中讀寫數據 
  6.         buffer.putInt(0,2018); 
  7.         System.out.println(buffer.getInt(0));        
  8.     } 

2. 什么是堆外內存?

Java 開發者一般都知道堆內存,但卻未必了解堆外內存。事實上,除了堆內存,Java 還可以使用堆外內存,也稱直接內存(Direct Memory)。

顧名思義,堆外內存是在 JVM Heap 之外分配的內存塊,并不是 JVM 規范中定義的內存區域,堆外內存用得并不多,但十分重要。

讀者也許會有一個疑問:既然已經有堆內存,為什么還要用堆外內存呢?這主要是因為堆外內存在 IO 操作方面的優勢。

舉一個例子:在通信中,將存在于堆內存中的數據 flush 到遠程時,需要首先將堆內存中的數據拷貝到堆外內存中,然后再寫入 Socket 中;

如果直接將數據存到堆外內存中就可以避免上述拷貝操作,提升性能。類似的例子還有讀寫文件。

目前,很多 NIO 框架 (如 netty,rpc) 會采用 Java 的 DirectByteBuffer 類來操作堆外內存,DirectByteBuffer 類對象本身位于 Java 內存模型的堆中,由 JVM 直接管控、操縱。

但是,DirectByteBuffer 中用于分配堆外內存的方法 unsafe.allocateMemory(size) 是個一個 native 方法,本質上是用 C 的 malloc 來進行分配的。

分配的內存是系統本地的內存,并不在 Java 的內存中,也不屬于 JVM 管控范圍,所以在 DirectByteBuffer 一定會存在某種特別的方式來操縱堆外內存。

3. 堆外內存創建過程深度解析

首先,我們來看一下 DirectByteBuffer 源代碼,從中洞悉分配堆外內存的過程:

3.1 ***個重要方法:

  1. Bits.reserveMemory(size, cap); 

源代碼如下:

該方法用于在系統中保存總分配內存(按頁分配)的大小和實際內存的大小,具體執行中需要首先用 tryReserveMemory 方法來判斷系統內存(堆外內存)是否足夠,具體代碼如下:

從 Bits.reserveMemory(size, cap) 源碼可以看出,其執行過程中,可能遇到以下三種情況:

1. 最樂觀的情況:可用堆外內存足夠,reserveMemory 方法返回 true,該方法結束。

2. 如果不幸,堆外內存不足,則須進行第二步:

  1. jlra.tryHandlePendingReference() 

 會觸發一次非堵塞的 

Reference#tryHandlePending(false),該方法會將已經被 JVM 垃圾回收的 DirectBuffer 對象的堆外內存釋放。

3. 如果在進行一次堆外內存資源回收后,還不夠進行本次堆外內存分配的話,則進行 GC 操作:

System.gc() 會觸發一個 Full GC,當然,前提是你沒有顯示的設置 - XX:+DisableExplicitGC 來禁用顯式 GC。同時,需要注意的是,調用 System.gc() 并不能夠保證 Full GC 馬上就能被執行。

調用 System.gc() 后,接下來會最多進行 9 次循環嘗試,仍然通過 tryReserveMemory 方法來判斷是否有足夠的堆外內存可供分配操作。每次嘗試都會 sleep,以便 Full GC 能夠完成,如下代碼所示。

4. 最不幸的情況,經過 9 次循環嘗試后,如果仍然沒有足夠的堆外內存,將拋出 OutOfMemoryError 異常。

綜上所述,Bits.reserveMemory(size, cap) 方法將依次執行以下操作:

1.如果可用堆外內存足以分配給當前要創建的堆外內存大小時,直接返回 True;

2.如果堆外內存不足,則觸發一次非堵塞的 Reference#tryHandlePending(false)。該方法會將已經被 JVM 垃圾回收的 DirectBuffer 對象的堆外內存釋放;

3.如果進行一次堆外內存資源回收后,還不夠進行本次堆外內存分配的話,則進行 System.gc()。

System.gc() 會觸發一個 Full GC,需要注意的是,調用 System.gc() 并不能夠保證 Full GC 馬上就能被執行。

所以在后面打代碼中,會進行最多 9 次嘗試,看是否有足夠的可用堆外內存來分配堆外內存。

并且每次嘗試之前,都對延遲等待時間,已給 JVM 足夠的時間去完成 Full GC 操作。

4.如果 9 次嘗試后依舊沒有足夠的可用堆外內存來分配本次堆外內存,則拋出 OutOfMemoryError(“Direct buffer memory”) 異常。

3.2 第二個重要方法:

unsafe.allocateMemory(size)

......

3.3 第三個重要方法:

Cleaner.create(this, new Deallocator(base, size, cap))

......

責任編輯:武曉燕 來源: GitChat精品課
相關推薦

2017-01-15 17:48:04

Java開發者編程語言

2016-12-26 17:53:05

Java開發者編程語言

2017-02-05 16:00:35

Java編程語言

2016-08-05 16:28:05

javascripthtml前端

2022-10-26 07:21:15

網絡視頻開發

2017-06-26 15:32:59

前端編譯原理語言知識

2013-04-19 09:23:34

2013開發者開發趨勢和技能

2011-09-20 09:27:50

Web

2020-03-04 11:20:22

DSL開發領域特定語言

2021-05-10 10:01:04

JavaScript開發技巧

2012-02-06 09:14:24

2012-06-26 10:13:55

2011-04-01 11:16:06

hessian

2020-04-03 09:00:00

微服務前端架構

2013-07-10 11:11:05

PythonGo語言

2021-02-07 09:02:28

內存管理length

2012-06-27 09:11:47

2018-09-29 15:27:05

BinderAPPAndroid

2014-12-15 10:25:21

移動開發像素設計

2016-12-19 15:55:10

PHP開發者Composer
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久久资源 | 亚洲成人一区 | 日韩资源| 爱爱视频日本 | 国产亚洲欧美在线 | 成人福利网 | 欧美综合在线观看 | 国产精品亚洲综合 | 一级做a爰片性色毛片16 | 亚洲福利视频网 | 一级毛片大全免费播放 | av免费网站在线观看 | 国产精品久久久久久av公交车 | 免费在线看黄 | 午夜精品一区二区三区三上悠亚 | 精品国产精品国产偷麻豆 | 97精品一区二区 | 亚洲欧美一区在线 | 视频在线一区二区 | 91大神在线看 | 亚洲精品乱码久久久久久久久久 | 成人av在线网站 | 五月婷婷 六月丁香 | 亚洲精选久久 | 91精品国产综合久久小仙女图片 | 99久久婷婷国产综合精品电影 | 欧美区在线| 久久一| 国产精品视频网站 | 国产亚洲一区二区三区在线 | 成人黄色av网站 | 国产日韩欧美精品一区二区三区 | 成人久久久久 | 神马久久久久久久久久 | 在线成人免费观看 | 欧美成人a | 亚洲成人久久久 | 电影午夜精品一区二区三区 | 国产福利视频在线观看 | 免费久久网站 | 91欧美|