介紹TLB以前,咱們先來回顧一個操做系統裏的基本概念,虛擬內存。php
在用戶的視角里,每一個進程都有本身獨立的地址空間,A進程的4GB和B進程4GB是徹底獨立不相關的,他們看到的都是操做系統虛擬出來的地址空間。可是呢,虛擬地址最終仍是要落在實際內存的物理地址上進行操做的。操做系統就會經過頁表的機制來實現進程的虛擬地址到物理地址的翻譯工做。其中每一頁的大小都是固定的。這一段我不想介紹的太過於詳細,對這個概念不熟悉的同窗回去翻一下操做系統的教材。 redis
頁表管理有兩個關鍵點,分別是頁面大小和頁表級數緩存
在Linux下,咱們經過以下命令能夠查看到當前操做系統的頁大小數據結構
# getconf PAGE_SIZE 4096
能夠看到當前個人Linux機器的頁表是4KB的大小。ide
2.頁表級數函數
爲了幫助你們回憶這段知識,我舉個例子。若是想支持32位的操做系統下的4GB進程虛擬地址空間,假設頁表大小爲4K,則共有2的20次方頁面。若是採用速度最快的1級頁表,對應則須要2的20次方個頁表項。一個頁表項假如4字節,那麼一個進程就須要(1048576*4=)4M的內存來存頁表項。
若是是採用2級頁表,如圖1,則建立進程時只須要有一個頁目錄就能夠了,佔用(1024*4)=4KB的內存。剩下的二級頁表項只有用到的時候纔會再去申請。 工具
如今的操做系統須要支持的但是48位地址空間(理論上能夠支持64位,但其實如今只支持到了48位,也足夠用了),並且要支持成百上千的進程,若是不採用分級頁表的方式,則建立進程時就須要爲其維護一個2的36次方個頁表項(64位Linux目前只使用了地址中的48位的,在這裏面,最後12位都是頁內地址,只有前36位纔是用來尋找頁表的), 2^36 *4Byte=32GB,這個更不能忍了。 也必須和32位系統同樣,進一步提升頁表的級數。 性能
Linux在v2.6.11之後,最終採用的方案是4級頁表,分別是:spa
這樣,一個64位的虛擬空間,初始建立的時候只須要維護一個2^9 大小的一個頁全局目錄就夠了,如今的頁表數據結構被擴展到了8byte。這個頁全局目錄僅僅須要(2^9 *8=)4K,剩下的中間頁目錄、頁表項只須要在使用的時候再分配就行了。Linux就是經過這種方式支持起(2^48 =)256T的進程地址空間的。操作系統
上面終於費勁扒了半天Linux虛擬內存的實現,我終於能夠開始說我想說的重點了。
雖然建立一個支持256T的地址空間的進程在初始的時候只須要4K的頁全局目錄,可是,這也帶來了額外的問題,頁表是存在內存裏的。那就是一次內存IO光是虛擬地址到物理地址的轉換就要去內存查4次頁表,再算上真正的內存訪問,最壞狀況下須要5次內存IO才能獲取一個內存數據!!
和CPU的L一、L二、L3的緩存思想一致,既然進行地址轉換須要的內存IO次數多,且耗時。那麼幹脆就在CPU裏把頁表儘量地cache起來不就好了麼,因此就有了TLB(Translation Lookaside Buffer),專門用於改進虛擬地址到物理地址轉換速度的緩存。其訪問速度很是快,和寄存器至關,比L1訪問還快。
我原本想實際看一下TLB的信息,但翻遍了Linux的各類命令,也沒有找到像sysfs這麼方便查看L一、L二、L3大小的方法。僅僅提供下圖供你們參考吧! (誰要是找到了查看TLB的命令,別忘了分享給飛哥啊,謝謝!)
有了TLB以後,CPU訪問某個虛擬內存地址的過程以下
因爲第2步是相似於寄存器的訪問速度,因此若是TLB能命中,則虛擬地址到物理地址的時間開銷幾乎能夠忽略。若是想了解TLB更詳細的工做機制,請參考《深刻理解計算機系統-第9章虛擬內存》
既然TLB緩存命中很重要,那麼有什麼工具可以查看你的系統裏的命中率呢? 還真有
# perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses -p $PID Performance counter stats for process id '21047': 627,809 dTLB-loads 8,566 dTLB-load-misses # 1.36% of all dTLB cache hits 2,001,294 iTLB-loads 3,826 iTLB-load-misses # 0.19% of all iTLB cache hits
由於TLB並非很大,只有4k,並且如今邏輯核又形成會有兩個進程來共享。因此可能會有cache miss的狀況出現。並且一旦TLB miss形成的後果可比物理地址cache miss後果要嚴重一些,最多可能須要進行5次內存IO才行。建議你先用上面的perf工具查看一下你的程序的TLB的miss狀況,若是確實不命中率很高,那麼Linux容許你使用大內存頁,不少大牛包括PHP7做者鳥哥也這樣建議。這樣將會大大減小頁表項的數量,因此天然也會下降TLB cache miss率。所要承擔的代價就是會形成必定程度的內存浪費。在Linux裏,大內存頁默認是不開啓的。
開發內功修煉之CPU篇專輯:
個人公衆號是「開發內功修煉」,在這裏我不是單純介紹技術理論,也不僅介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提升你的技術實踐能力。歡迎你來關注個人公衆號,也請分享給你的好友~~~