【Java】Java中的零拷貝

物理內存
計算機物理內存條的容量 , 比如我們買電腦會關注內存大小有多少G , 這個容量就是計算機的物理內存 。
【【Java】Java中的零拷貝】虛擬內存
操作系統為每個進程分配了獨立的虛擬地址空間,也就是虛擬內存,虛擬地址空間又分為用戶空間和內核空間,操作系統的位數不同 , 虛擬地址空間的大小也不同 , 32位操作系統虛擬地址內核空間為1G , 用戶空間大小為3G , 64位操作系統用戶空間和內核空間大小各為128T:

【Java】Java中的零拷貝

文章插圖
既然每個進程都擁有一塊獨立的虛擬地址空間,那么所有進程的虛擬地址空間大小加起來必定大于物理內存的大?。?所以虛擬地址空間只是一個虛擬的概念,只有需要分配內存的時候才會為虛擬內存分配物理內存 , 并通過內存映射來管理虛擬地址和物理內存地址之間的映射關系 。
用戶空間 / 內核空間
用戶空間:是運行用戶程序代碼的地方,為了保證系統內核的安全,它不能直接訪問內存等硬件設備,必須通過系統調用進入到內核空間來訪問那些受限的資源 。
內核空間:是運行內核代碼的地方 , 可以執行任意的指令訪問系統資源 , 既可以訪問內核空間也可以訪問用戶空間 。
用戶態:進程運行在用戶空間時處于用戶態 。
內核態:進程運行在內核空間時處于內核態 。
文件I/O文件I/O與讀寫文件有關,比如我們啟動了一個程序,此時運行在用戶空間(用戶態),接著準備做一個讀取磁盤文件的操作,由于用戶空間是無法直接從磁盤讀取文件的,所以需要調用內核提供的接口來完成文件的讀?。?調用內核的接口的過程中由用戶空間進入到了內核空間(內核態),DMA從磁盤讀取文件到內核的緩沖區 , 之后再將數據從內核的緩沖區拷貝到用戶空間完成文件的讀取操作:
【Java】Java中的零拷貝

文章插圖
  1. 應用程序調用read函數發起系統調用,此時由用戶空間切換到內核空間;
  2. 內核通過DMA從磁盤拷貝數據到內核緩沖區(DMA復制);
  3. 將內核緩沖區的數據拷貝到用戶空間的緩沖區(CPU復制),切換回用戶空間;
可以發現,整個讀取過程發生了兩次數據拷貝,一次是DMA將磁盤上的文件數據拷貝到內核緩沖區,一次是將內核緩沖區的數據拷貝到用戶緩沖區 。寫操作與讀取操作類似 , 只不過是將用戶緩沖區的數據拷貝到內核緩沖區 , 再將內核緩沖區的數據拷貝到文件 。
文件I/O從操作系統的角度來看還可以劃分為緩存I/O、直接I/O和mmap內存映射 。
緩存I/O也稱標準I/O,上面提到的文件I/O讀取數據的例子就是使用的緩存I/O , 它需要將數據先拷貝到內核緩沖區 , 再將內核緩沖區的數據拷貝到用戶緩沖區 , 數據經過兩次拷貝,內核緩沖區和用戶緩沖區分別指向不同的物理內存 , 在文件I/O中 , 內核緩沖區是在Page Cache層 , 這也是稱為緩存I/O的原因:
【Java】Java中的零拷貝

文章插圖
JAVA中通過java.io包下進行讀寫文件使用的就是緩存I/O 。
為什么需要緩存IO?
因為磁盤I/O是比較耗時的操作 , 如果每次都從磁盤上讀取文件 , 性能將會大大下降,為了提升讀取性能,增加了一層Page Cache,用于緩存讀取的文件數據,Page Cache占用的是內存,從內存讀取的速度遠遠大于從磁盤讀?。諍嘶撼邇褪竊赑age Cache中開辟的一塊內存,用戶空間進行系統調用讀取文件內容時,首先會判斷Page Cache中是否緩存了文件的內容,如果緩存了直接讀取即可,否則再從磁盤讀??,所以缓存I/O可以減少磁盤I/O的次數提升性能 。
文件的寫操作同樣如此 , 進行寫操作時,將數據先寫到Page Cache的緩沖區中,后續由操作系統將數據刷回到磁盤中 。
緩存I/O的優缺點
優點:減少磁盤I/O次數,提升讀寫性能 。
缺點:數據需要在內核空間和用戶空間來回拷貝 。
DirectByteBuffer使用緩存I/O讀取數據時,數據會經過兩次拷貝 , 經過兩次拷貝是從系統調用開始講起,在JAVA中由于涉及到JVM堆內和堆外內存,如果使用java.io下的類進行文件讀寫實際上還會再多一次拷貝(詳細可參考【JAVA】普通IO數據拷貝次數的問題探討):

推薦閱讀