内存的概念模型
内核為了更方便的讓我們去操作物理内存,引入了虛拟地址這個概念。
如果沒有虛拟地址,那我們程序直接操作的是物理地址,那每一塊物理内存一次性取多少?
取完之後再放回去的時候,由于每一次取的大小不固定,産生的内存間隙又該如何去處理?
所以内核為了解決這種問題引入了虛拟地址。
實際的物理地址的分配以及物理地址的存取是由内核去完成的,用虛拟地址最後會映射成物理地址,才會去實際的從主存上面拿取數據。
關于實際上數據的存取是由内核幫助我們完成的。每個用戶進程隻能看見自己空間的地址。在cpu處理的時候,cpu會把這個地址通過mmu轉變成物理地址。
mmu的工作流程
首先是中央處理器(cpu)在得到一個虛拟地址之後,會從一級緩存裡面去尋找這個虛拟地址對應的數據在不在,不在的話,就會從存儲器管理單元(mmu),mmu會有一個頁表的結構,這個頁表本來是在主存上面的,但是如果每次mmu都從主存上面去拉取這個頁表的映射信息,肯定會比較慢了,所以mmu又引入了轉址旁路緩存(tlb),它是一塊硬件設備,是和mmu靠在一起的。
當mmu在尋找這個映射關系的時候,先從tlb上面去尋找這個映射關系,如果是找不到的話,那它才會在主存上面的頁表上面去拉取這個映射關系,最終得到了物理地址之後,它會進到cpu的一個二級緩存裡面去尋找,二級緩存裡面找不到,會再從三級緩存裡面去尋找數據,再找不到那就從主存裡面去獲取這個數據了。
頁交換
當系統内存比較吃緊的時候,内核會交換一部分的内存頁到磁盤上,等到需要的時候,會再從磁盤上把那個内存頁讀取到主存裡面去,如果是内存頁被交換到磁盤上之後,再從磁盤的讀回來,這整個過程是一個比較消耗性能的,如果整個系統在頻繁的去進行頁交換,那很有可能頁交換會造成瓶頸,而根本原因是内存空間不足了,得加一個内存條。
如何分析内存性能問題?
先從整體上去把握整個系統内存的情況,首先來看下内存的使用率、飽和度、錯誤數等。
針對于内存而言,它的一個使用率就是說它使用的内存空間的大小占總的大小的多少。
内存飽和度就是頁交換的次數,如果内存頻繁的去進行頁交換,那可以認為内存現在是處于一種飽和的狀态。
通過top命令 我們能夠去看到整個系統的一個内存情況,top後輸入E,切換内存換算單位,默認為字節,
buff/cache
對文件進行操作的時候,會經由文件系統和磁盤打交道,當我們寫一個字符串或寫一段文本到文件裡的時候,它不會立馬刷到磁盤裡去,進入文件系統它會先存到一個緩存裡,這個緩存叫做page cache,也就是buffer/cache裡的cache。會有一個進程在執行一個刷盤的操作,刷盤的話會把這個cache裡面的數據真正的寫入到磁盤上面去。讀文件也是類似,當我們讀文件的時候,先從文件系統的page cache裡面去讀,讀不到的時候,它才會真正的從磁盤上面去讀真正的文件數據。
在老的linux系統上,這兩個值其實是分開的,但如果這兩個值分開的話,比如說我讀文件,先到buffer,再到cache,再到應用程序裡面的話,這個數據就相當于被多複制了一份,在新版的linux系統,讀文件時,cache已經指向了buffer,這樣的話,就減少了一次數據的複制過程。
内存的飽和度
内存的飽和度是用頁交換去衡量的,通過sar -W的命令可以去看系統的頁交換次數,
這裡會每秒刷新一次頁交換的次數(換進換出的次數)。
那如果整個系統頻繁的進行頁交換之後,很有可能内存已經處于一種比較吃緊的狀态了,需要去加内存條。
上面看了系統層面的内存使用情況,再定位到具體的進程。
通過top命令輸入M,會把内存從大到小進行排序,從而找出最消耗内存的一個進程。
定位到具體的進程之後,可以去分析進程具體是什麼原因導緻内存消耗過大。
查看進程使用内存的情況
可以用pidstat命令去看這個進程使用的内存的情況,
pidstat -r -p pid
缺頁異常的次數
缺頁異常的次數也是我們平時要經常關注的一個點。majflt指的是一個主的缺頁次數,主的缺頁次數指的是當要讀取内存頁的時候,這個内存頁實際是在磁盤上的,在讀取的時候,它要被内核交換到内存上面來,所産生的這種缺頁異常會記錄到這裡,而除此以外的缺頁異常都會被minflt記錄。如果主的這個缺頁異常過多,也可以從側面反映出這個進程在進行過多的這種頁交換,而頁交換所導緻的問題就是系統的性能肯定是上不去的。
在golang裡面如何去看具體的哪一段代碼導緻的内存占用問題?
官方提供的go tool pprof工具可以分析内存的profile文件,通過分析這個profile文件,我們能夠找出具體是哪段代碼導緻的問題。通過go tool pprof --base這個命令是能夠比較兩個内存的profile文件,這也是排查golang程序内存洩漏經常用到的一個手段,也很方便的能夠找出問題代碼。在golang裡可以很方便查看整個内存的使用情況從操作系統到進程再到具體的代碼段整個過程。
内存洩漏問題如何排查?
内存洩漏的表現就是内存在不斷的增長,而不斷增長後可能整個系統就會頻繁的進行換頁的動作。
在golang程序裡面能夠通過比較兩次的内存的profile文件,看下具體是哪段代碼導緻内存在不斷增長,從而去找出内存洩漏的那段問題代碼。
特别是針對開發來講,排查下性能優化的最終原因,其實大部分都是由于你的問題代碼導緻的,我們得學會如何找出這段問題代碼。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!