前面幾部分主要從原理上講解了linux核心如何管理核心態記憶體與使用者態記憶體,這部分我們重點**記憶體管理中一些實際工程上的效能問題。
1 為何需要記憶體對齊?
記憶體對齊是一種提供記憶體訪問速度的策略,cpu在訪問未對齊的記憶體需要經過兩次記憶體訪問,而經過記憶體對齊一次就可以。這是根據cpu位數決定的,32位cpu一次的取指能力為4個位元組,如果不做記憶體對齊,很可能乙個4位元組的變數會處於兩個4位元組的記憶體塊中,這樣就需要cpu訪問記憶體兩次。可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的「對齊係數」。
2 程序位址空間各段的分配情況?
測試**:
#include
static int d=100;
void main()
執行結果:
0x7fff31b0f47c 0x7fff31b0f478
0x7fff31b0f470 0x7fff31b0f474
0x6008c4
我們看到使用者空間棧是逆向增長的a,b都是分配在棧上,其中a分配在bss段上,堆是正向增長的c[0],c[1]分配在堆上,d是全域性靜態常量區,它分布在全域性靜態常量儲存區,它的位址與其它變數位址相差較大。而且全域性靜態常量區位址一旦分定,二次執行不會發生變化。
3 oom_killer機制
所謂oom_killer就是當系統的物理記憶體與交換分割槽都被用盡時,再有新的程序要申請記憶體時,核心將觸發oom_killer。在centos系統中該機制按照如下準則執行:
/proc/sys/vm/panic_on_oom為0,證明不會觸發panic
/proc/sys/vm/oom_kill_allocating_task為0核心將檢查每個程序的分數,分數最高的程序將被kill掉。/proc/sys/vm/oom_dump_tasks為1,且系統的rlimit中設定了core檔案大小,將會由/proc/sys/kernel/core_pattern裡面指定的程式生成core dump檔案,這個檔案裡將包含pid, uid, tgid, vm size, rss, nr_ptes, nr_pmds, swapents, oom_score_adj,score, name等內容,拿到這個core檔案之後,可以做一些分析,看為什麼這個程序被選中kill掉。
測試**:
#include
#define max 10000000
void main()
}在後台執行該程序,pid號為6048。執行cat /proc/6048/status會發現該程序的變化如下:
該程序位址空間不斷增長,然後 free-m:
物理記憶體不斷被消耗,交換分割槽的記憶體也不斷被消耗。
執行cat /proc/6048/oom_score觀察如下:
程序的oom_score不斷增長,最後交換分割槽與物理記憶體都被用盡,系統檢查分數最高的程序並kill掉。
4 缺頁異常處理機制
當mmu中確實沒有建立虛擬頁物理頁對映關係,並且在該虛擬位址之後再沒有當前程序的線性區vma的時候,可以肯定這是乙個編碼錯誤,這將殺掉該程序;
當mmu中確實沒有建立虛擬頁物理頁對映關係,並且在該虛擬位址之後存在當前程序的線性區vma的時候,這很可能是缺頁異常,並且可能是棧溢位導致的缺頁異常;
當使用malloc/mmap等希望訪問物理空間的庫函式/系統呼叫後,由於linux並未真正給新建立的vma對映物理頁,此時若先進行寫操作,將如上面的2的情況產生缺頁異常,若先進行讀操作雖也會產生缺頁異常,將被對映給預設的零頁(zero_pfn),等再進行寫操作時,仍會產生缺頁異常,這次必須分配物理頁了,進入寫時複製的流程;
當使用fork等系統呼叫建立子程序時,子程序不論有無自己的vma,「它的」vma都有對於物理頁的對映,但它們共同對映的這些物理頁屬性為唯讀,即linux並未給子進**正分配物理頁,當父子程序任何一方要寫相應物理頁時,導致缺頁異常的寫時複製;
Redis學習日記(五) 記憶體管理
這裡有3個內容我們得注意 used memory 物理使用的記憶體空間 1.97m user memory rss 作業系統認為redis使用的記憶體空間。這裡是 2.59m mem fragmentstion ratio 的值 1 表示記憶體碎片化嚴重 1 說明redis記憶體存在硬碟化情況 re...
OC重新開始(五)記憶體管理MRC
在程式裡,若執行過程中不但不能釋放不在使用的記憶體反而會不停的分配記憶體這樣占用的記憶體會越來越多,程式速度會越來越慢最後甚至會崩潰。在指標所指向的物件已經被釋放或 的情況下,改指標被稱為野指標或懸垂指標,繼續使用這樣的指標會造成程式崩潰。oc中通過向類物件傳送alloc訊息來生成例項物件,allo...
記憶體管理五
本例在建立乙個新的堆前後分別通過 getprocessheaps 函式獲取了當前程序的堆控制代碼列表,沒想到乙個最簡單的程式也有 5 個堆.效果圖 list.add format 當前程序共有 d 個堆 n list.add 它們的控制代碼分別是 fori 0 ton 1 do list.add i...