目錄
一篙程、I/O調優(yōu)的重要性
二枷畏、數據傳輸過程
1.磁盤到緩存區(qū)運動過程
2.零字節(jié)拷貝
三、虛擬內存
1.虛擬內存好處
2.內存頁調度
四虱饿、文件I/O
1.分頁技術操作系統(tǒng)執(zhí)行I/O的過程
2.文件鎖定
五拥诡、場景回顧
六、知識來源
一氮发、I/O調優(yōu)的重要性
I/O操作比內存中數據處理任務的時間更長渴肉,差別以數量級計。
第一列為處理一個數據單元所需要的時間爽冕,第二列為對該數據單元進行磁盤讀寫所需要的時間仇祭,第三列為每秒能處理的數據單元數,第四列為改變第一列第二列的值所能產生的數據吞吐率的提升颈畸。
圖中相對說明:單位處理時間減半乌奇,僅能提高吞吐率2.2%,I/O時間減半眯娱,吞吐幾乎翻倍礁苗。
操作系統(tǒng)移動的是大塊數據(緩存區(qū)),而java.io類喜歡操作小塊數據--單個字節(jié)困乒、幾行文本寂屏,有了NIO就可以輕松把大塊數據備份到直接使用的地方(ByteBuffer對象)贰谣。
備注:應該將I/O擺在性能調優(yōu)的第一位娜搂,代碼調試放在第二位迁霎。
二、數據傳輸過程
1.磁盤到緩存區(qū)運動過程
緩存區(qū)如何工作百宇,是所有I/O的基礎考廉。輸入/輸出無非就是把數據移進或移出緩存區(qū)。
數據從磁盤向運行中的進程的內存區(qū)域移動的過程
1.進程使用read()系統(tǒng)調用携御,要求其緩存區(qū)被填滿
2.內核隨機向磁盤控制硬件發(fā)出命令昌粤,要求從磁盤讀取數據。
3.磁盤控制器把數據直接寫入內核緩存區(qū)啄刹,這一步通過DMA完成涮坐,無需主CPU協(xié)助。
4.一旦磁盤控制器把緩存區(qū)裝滿誓军,內核即把數據從內核空間額臨時緩存區(qū)拷貝到進程執(zhí)行read()調用時指定的緩存區(qū)袱讹。
用戶空間:即常規(guī)線程所在區(qū)域,非特權區(qū)域昵时,不能直接訪問設備捷雕,JVM即常規(guī)線程,駐守于用戶空間壹甥。
內核空間:是操作系統(tǒng)所在的區(qū)域救巷,特權區(qū)域,能與設備控制器進行通信句柠,控制者用戶區(qū)域空間進程的運行狀態(tài)等浦译。
所有的I/O都直接或者間接的通過內核空間。
進程一個系統(tǒng)調用溯职,將一連串緩存區(qū)地址傳遞給操作系統(tǒng)管怠,內核按順序填充或者排干若干緩沖區(qū),讀的時候可以發(fā)散到多個用戶緩存區(qū)缸榄,寫的時候可以從多個用戶緩存區(qū)把數據匯聚起來渤弛。
備注:內核試圖對數據進行高速緩存或者預讀取,所以進程所需要數據可能已經在內核空間里了甚带,已在內核空間的只需要拷貝該數據即可她肯。如果不在內核空間,則進程被掛起鹰贵,內核將數據讀到內存晴氨。
2.零字節(jié)拷貝
傳統(tǒng)數據從文件傳到套接字的路徑
一般的將數據從文件傳到套接字的路徑:
1.操作系統(tǒng)將數據從磁盤讀到內核空間的頁緩存中;
2.應用將數據從內核空間讀到用戶空間的緩存中碉输;
3.應用將用戶空間數據寫回內存空間的套接字緩存中籽前;
4.操作系統(tǒng)將數據從套接字緩存寫到網卡緩存中,以便將數據經網絡發(fā)出;
這里有四次拷貝
零字節(jié)拷貝方式
拷貝路徑
1.transferTo() 中文件內容被DMA引擎加載入內核buffer
2.數據不再被拷入socket buffer被取代的只有descriptor關于位置和長度的信息追加到socket buffer枝哄,DMA引擎將數據直接從內核buffer拷貝到網卡緩存
如果使用sendfile(Java 為: FileChannel.transferTo api)肄梨,兩次拷貝可以被避免:允許操作系統(tǒng)將數據直接從頁緩存發(fā)送到網絡上
注:DMA(Direct Memory Access,直接內存存取) 傳輸將數據從一個地址空間復制到另外一個地址空間
三挠锥、虛擬內存
1.虛擬內存好處
1.一個或者多個的虛擬地址可以指向同一個物理內存地址
2.虛擬內存空間可大于實際可用的硬件內存
下圖用戶空間和內核空間地址映射到同一個物理內存地址
把內核空間地址與用戶空間的虛擬地址映射到同一個物理地址众羡,可以省去內核與用戶空間拷貝;前提條件為:
1.內核與用戶緩存區(qū)必須使用相同的頁對齊
2.緩沖區(qū)的大小需磁盤控制器塊大斜妥狻(通常512字節(jié))的倍數
3.內存頁的大小總是磁盤塊大小的倍數(操作系統(tǒng)把內存地址空間劃分為頁)
4.虛擬和物理內存頁的大小總是相同
2.內存頁調度
為了支持尋址空間大于物理內存粱侣,虛擬內存需要分頁(通常稱為交換)。分頁區(qū)即從物理內存置換出來蓖宦,存儲在磁盤上的內存頁面齐婴。
進程A有5個頁面,其中兩個裝入內存稠茂,其余存儲于磁盤尔店。
CPU中包含內存管理單元(MMU),邏輯上位于CPU與物理內存之間主慰,該設備包含虛擬地址向物理內存地址轉換的映射信息嚣州。
當不存在與該虛擬頁形成有效映射物理內存頁,MMU會向CPU提交一個頁錯誤共螺,內核驗證頁的有效性该肴,內核會安排頁面調入操作,把缺失的頁面內容讀回物理內存藐不,通常此時別的頁面會移除內存匀哄。
四、文件I/O
1.分頁技術操作系統(tǒng)執(zhí)行I/O的過程
當用戶進程請求讀取文件數據時雏蛮,文件系統(tǒng)需要確定數據具體在磁盤什么位置涎嚼,然后著手把相關磁盤扇區(qū)讀進內存。
采用分頁技術的操作系統(tǒng)執(zhí)行I/O的過程:
1.確定請求數據分布在文件系統(tǒng)的哪些頁
2.在內核空間分配足夠的內存頁挑秉,以容納文件系統(tǒng)頁
3.在內存頁與磁盤的文件系統(tǒng)頁之間建立映射
4.為每個內存頁產生頁錯誤
5.虛擬內存系統(tǒng)俘獲頁錯誤法梯,安排頁面調入,從磁盤上讀取頁內容犀概,使頁有效立哑。
6.一旦頁面調入操作完成,文件系統(tǒng)即對原始數據進行解析姻灶,取得所需文件內容或屬性
信息
備注:大多數操作系統(tǒng)假設進程會繼續(xù)讀取文件剩余部分铛绰,因而會預讀額外的文件系統(tǒng)頁。如果內存 爭用情況不嚴重产喉,這些文件系統(tǒng)頁可能在相當長的時間內繼續(xù)有效捂掰。這樣的話敢会,當稍后該文件又被 相同或不同的進程再次打開,可能根本無需訪問磁盤这嚣。
2.文件鎖定
文件鎖定機制允許一個進程阻止其他進程存取某文件鸥昏,或限制其存取方式。
文件鎖定有兩種方式:共享的和獨占的疤苹。多個共享鎖可同時對同一文件區(qū)域發(fā)生作用;獨占鎖
則不同,它要求相關區(qū)域不能有其他鎖定在起作用敛腌。
共享鎖和獨占鎖的經典應用:
共享鎖和獨占鎖的經典應用卧土,是控制最初用于讀取的共享文件的更新。某個進程要讀取文件像樊, 會先取得該文件或該文件部分區(qū)域的共享鎖尤莺。第二個希望讀取相同文件區(qū)域的進程也會請求共享鎖。兩個進程可以并行讀取生棍,互不影響颤霎。假如有第三個進程要更新該文件,它會請求獨占鎖涂滴。該進程會處于阻滯狀態(tài)友酱,直到既有鎖定(共享的、獨占的)全部解除柔纵。一旦給予獨占鎖缔杉,其他共享鎖的讀取進程會處于阻滯狀態(tài),直到獨占鎖解除搁料。
五或详、場景回顧
在RocketMQ創(chuàng)建commitLog文件預熱時,寫入1G大小的假值(0)的意義郭计。
使用mmap()內存分配時霸琴,只是建立了進程虛擬地址空間,并沒有分配虛擬內存對應的物理內存昭伸。當進程訪問這些沒有建立映射關系的虛擬內存時物舒,處理器自動觸發(fā)一個缺頁異常,進而進入內核空間分配物理內存送爸、更新進程緩存表枕磁,最后返回用戶空間,恢復進程運行辑莫。如果沒有這些假值学歧,系統(tǒng)不會實際分配物理內存,防止在寫入消息時發(fā)生缺頁異常各吨。
六枝笨、知識來源
本文整理自《Java NIO》第一章