關於記憶體,總是少不了tlb, cache,buffer, 最近有了點粗淺的概念理解。
處理器為每個processor都分配了虛擬位址,具體的map方式可以通過/proc/$/map 檢視程序的具體對映,這是通過mmu(記憶體管理單元)實現的。linux虛擬位址到實體地址的對映通過多級分頁方式(具體分級和體系結構有關),如果頁表是存在於主存中的,那麼我們針對這各級的頁表,都需要逐次訪問記憶體,這很慢,實際上,即使是把他們快取在cache中,也仍然很慢,因為各級之間的訪問並不能並行,必須要得到前面的訪問結果之後才能進行下乙個訪問,加上可能存在的cache miss,快取頻寬將會被消耗。所以針對這種快取條目目錄的方式,如果能針對虛擬位址一次性得到實體地址將會極大提公升效能,實際上,也是這麼做的。tlb(旁路轉換快取)就是mmu改進虛擬位址到實體地址轉換的方法,tlb實質上也是一種cache,它會將位址轉換中最頻繁出現的位址,儲存到tlb的高速cpu快取中,這樣就可以直接從tlb中直接取得位址資料。
當cpu執行讀操作時,需要將虛擬位址轉換為實體地址,在這裡需要訪問tlb,tlb儲存著虛擬位址前20位到頁框號的對映關係,之後根據得到的頁框號,再加上後面12位的物理偏移位址,就可以迅速定位到實體地址。如果tlb中虛擬位址不存在,就出現tlb丟失,需要到頁表中查詢頁表項(如果找到,需要將找到的頁表項替換tlb中的乙個條目), 如果在頁表中也不存在,則需要到磁碟中去取。
具體頁表的建立在這裡不做描述,目前linux是支援huge tlb的,因為隨著可用記憶體的加大,繼續使用4kb的分頁,將會導致大量的tlb miss 和 缺頁中斷。
在上下文切換時,都需要重新重新整理tlb,但是存在兩種情況避免重新整理tlb,實際上就我自己理解來說,需要的暫存器資料等都改變了,自然需要重新整理tlb,但是如果你需要的內容沒有被改變呢?
使用相同頁表的程序切換
普通程序切換到核心程序(lazy-tlb模式)
cache是為了解決高速cpu和慢速記憶體裝置之間的速率差異出現的,存在這l1 cache(l1d,l1i), l2 cache 和 l3 cache,出現較多的情況是l1 cache做在cpu內,為cpu私有,其指令和cpu一樣, l2 cache是sram,存在位置有在cpu外的,也有在cpu內的,速率略低於cpu指令週期;l3 cache是邏輯概念,為所有l2 cache的集合。
cache line 是 cache 和 dram 同步的最小單位,一般乙個 cache line 為 32位元組或者是 64 位元組,在第一次訪問一塊區域時,會將內容同時複製到cache中,之後讀寫訪問就可以通過cache 實現了。
針對需要讀寫的位址,分成三部分,高t位用來檢驗是否是cpu需要訪問的單元,s位用來計算該記憶體單元對映到哪乙個組,而最低的b位表示了該單元在cache line中的偏移量
乙個cahce分成s個組,每個組有e個cache line,每個cahe line中存在b個記憶體單元(1位元組),對應記憶體單元,很容易看出s = 2 ^ s, b = 2 ^ b。
一條 cache entry包含以下部分:
cache line, 即上圖中的per cache block,包含b個位元組(32位體系為4位元組,64位8位元組)
tag, 標記cache line對應記憶體的高t位,因為可能有多個記憶體位址對應到同乙個cache line(乙個cache line有b個單位), 所以這個位用來校驗是否是cpu需要訪問的記憶體單元
valid, 標記該cache line是否是有效的,如果該cache line並沒有記憶體對映,就是無效的
通過以上方法,如果cache hit,就直接得到cache line,如果cache miss,則會將記憶體中cache line的資料load 進處理的同時 load 進cache中。
cpu和cache的交換是以字為單位的,但是從上文可以看到,cahce 和 記憶體之間的交換是以塊(cahce line)為單位的,這樣就引出了快取對齊的概念,實際上就是記憶體邊界對齊,對齊的好處在於可以減少cache交換資料的次數。
比如現在有個變數int x, 32位機上占用4個位元組,如果它的起始位址是0x1234567f;那麼它占用的記憶體範圍就在0x1234567f-0x12345682之間。如果現在cache line長度為32個位元組,那麼每次記憶體同cache進行資料交換時,都必須取起始位址時32(0x20,起始位址後5位為0)倍數的記憶體位置開始的一段長度為32的記憶體同 cache line進行交換。如0x1234567f落在範圍0x12345660~0x1234567f上,但是0x12345680~0x12345682落在範圍 0x12345680~0x1234569f上,也就是說,為了將4個位元組的整數變數0x1234567f~0x12345682裝入cache,我們必須調入兩條cache line的資料。但是如果int x的起始位址按4的倍數對齊,比如是0x1234567c~0x1234567f,那麼必然會落在一條cache line上,所以每次訪問變數x就最多隻需要裝入一條cache line的資料了。比如現在一般的malloc()函式,返回的記憶體位址已經是8位元組對齊的,這個就是為了能夠讓大部分程式有更好的效能。
快取行對齊
快取記憶體控制器是針對資料塊,而不是位元組進行操作的。從程式設計的角度講,快取記憶體其實就是一組稱之為快取行 cache line 的固定大小的資料塊,其大小是以突發讀或者突發寫週期的大小 為基礎的。快取基本上來說就是把後面的資料載入到離cpu自己進的地方,對於cpu來說,它是不會乙個位元組乙個位元...
CPU快取記憶體行對齊
cpu的快取記憶體一般分為一級快取和二級快取,現今更多的cpu更是提供了 快取。cpu在執行時首先從一級快取讀取資料,如果讀取失敗則會從二級快取讀取資料,如果仍然失敗則再從記憶體中存讀取資料。而cpu從一級快取或二級快取或主記憶體中最終讀取到資料所耗費的時鐘週期差距是非常之大的。因此快取記憶體的容量...
JVM快取行對齊效能優化
快取是由多個快取行組成的,以快取行為基本單位,乙個快取行的大小一般為64位元組。因為快取行存在,當不同的執行緒在操作兩份不同的資料時,如果這兩份資料剛好位於同乙個快取行中,那麼彼此之間就會互相影響。所以為了解決偽共享的問題,就出現了快取行對齊的方式,也就是讓c d兩份資料分別獨佔乙個快取行,這樣就不...