1.程序的運行
對cpu來講,內存只是一個存放指令和數據的地方,具體的運算在cpu內完成。程序員
1.寄存器(Register)
是CPU內部很是小、很是快速的存儲部件,它的容量頗有限,對於32位的CPU,每一個寄存器通常能存儲32位(4個字節)的數據,對於64位的CPU,每一個寄存器通常能存儲64位(8個字節)的數據。爲了完成各類複雜的功能,現代CPU都內置了幾十個甚至上百個的寄存器,嵌入式系統功能單一,寄存器數量較少。編程
寄存器在程序的執行過程當中相當重要,不可或缺,它們能夠用來完成數學運算、控制循環次數、控制程序的執行流程、標記CPU運行狀態等。數組
2.緩存
雖然內存的讀取速度已經很快了,可是和CPU比起來,仍是有很大差距的,不是一個數量級的,若是每次都從內存中讀取數據,會嚴重拖慢CPU的運行速度,CPU常常處於等待狀態,無事可作。在CPU內部設置一個緩存,能夠將使用頻繁的數據暫時讀取到緩存,須要同一地址上的數據時,就不用大老遠地再去訪問內存,直接從緩存中讀取便可。緩存
2.虛擬內存(內存地址都是假的)
1.虛擬地址
把程序給出的地址看作是一種虛擬地址(Virtual Address),而後經過某些映射的方法,將這個虛擬地址轉換成實際的物理地址。這樣,只要咱們可以妥善地控制這個虛擬地址到物理地址的映射過程,就能夠保證程序每次運行時均可以使用相同的地址。函數
除了在編程時可使用固定的內存地址,給程序員帶來方便外,使用虛擬地址還可以使不一樣程序的地址空間相互隔離,提升內存使用效率。佈局
使用了虛擬地址後,程序A和程序B雖然均可以訪問同一個地址,但它們對應的物理地址是不一樣的,不管如何操做,都不會修改對方的內存。spa
2.提升內存使用效率
使用虛擬地址後,操做系統會更多地介入到內存管理工做中,這使得控制內存權限成爲可能。例如,咱們但願保存數據的內存沒有執行權限,保存代碼的內存沒有修改權限,操做系統佔用的內存普通程序沒有讀取權限等。操作系統
3.內存對齊,提升尋址效率
將一個數據儘可能放在一個步長以內,避免跨步長存儲,這稱爲內存對齊。線程
在32位編譯模式下,默認以4字節對齊;在64位編譯模式下,默認以8字節對齊。blog
內存對齊由編譯程序實現,編譯時咱們能夠設置對齊長度。
4.內存分頁機制
現代計算機都使用分頁(Paging)的方式對虛擬地址空間和物理地址空間進行分割和映射,以減少換入換出的粒度,提升程序運行效率。
分頁(Paging)的思想是指把地址空間人爲地分紅大小相等(而且固定)的若干份,這樣的一份稱爲一頁,就像一本書由不少頁面組成,每一個頁面的大小相等。如此,就可以以頁爲單位對內存進行換入換出:
- 當程序運行時,只須要將必要的數據從磁盤讀取到內存,暫時用不到的數據先留在磁盤中,何時用到何時讀取。
- 當物理內存不足時,只須要將原來程序的部分數據寫入磁盤,騰出足夠的空間便可,不用把整個程序都寫入磁盤。
頁的大小由硬件決定,或硬件支持多種,由操做系統選擇一種大小,只能選一種。
內存分頁由操做系統決定管理。
5.Linux下c語言程序的內存佈局
內核空間和用戶空間
操做系統會默認將高地址的1G或2G空間分配給內核,剩下的內存空間是用戶空間
Linux下32位環境的用戶空間內存分佈狀況:
程序代碼區:主要存放二進制代碼。不可修改,有執行權限
常量區:存放通常的常量,有讀取權限,沒有修改權限。因此數據不能修改
全局數據區:存放全局變量,靜態變量等,有讀寫權限
堆區:由程序員分配和釋放,malloc(),calloc()等函數操做的內存
棧區:存放函數的參數,局部變量值
一個程序的代碼區,常量區,全局數據區在程序加載到內存的時候就分配好了,大小固定。
函數被調用時,會將參數、局部變量、返回地址等與函數相關的信息壓入棧中,函數執行結束後,這些信息都將被銷燬。因此局部變量、參數只在當前函數中有效,不能傳遞到函數外部,由於它們的內存不在了。
常量區、全局數據區、棧上的內存由系統自動分配和釋放,不能由程序員控制。程序員惟一能控制的內存區域就是堆(Heap):它是一塊巨大的內存空間,經常佔據整個虛擬空間的絕大部分,在這片空間中,程序能夠申請一塊內存,並自由地使用(放入任何數據)。堆內存在程序主動釋放以前會一直存在,不隨函數的結束而失效。在函數內部產生的數據只要放到堆中,就能夠在函數外部使用。
6.用戶模式和內核模式
內核空間存放的是操做系統內核代碼和數據,是被全部程序共享的,在程序中修改內核空間中的數據不只會影響操做系統自己的穩定性,還會影響其餘程序,這是很是危險的行爲,因此操做系統禁止用戶程序直接訪問內核空間。
要想訪問內核空間,必須藉助操做系統提供的 API 函數,執行內核提供的代碼,讓內核本身來訪問,這樣才能保證內核空間的數據不會被隨意修改,才能保證操做系統自己和其餘程序的穩定性。
用戶程序調用系統 API 函數稱爲系統調用(System Call);發生系統調用時會暫停用戶程序,轉而執行內核代碼(內核也是程序),訪問內核空間,這稱爲內核模式(Kernel Mode)。
用戶空間保存的是應用程序的代碼和數據,是程序私有的,其餘程序通常沒法訪問。當執行應用程序本身的代碼時,稱爲用戶模式(User Mode)。
7.棧的概念以及棧溢出
棧的概念:
棧內存由系統自動分配和釋放:發生函數調用時就爲函數運行時用到的數據分配內存,函數調用結束後就將以前分配的內存所有銷燬。因此局部變量、參數只在當前函數中有效,不能傳遞到函數外部。
在計算機中,棧能夠理解爲一個特殊的容器,用戶能夠將數據依次放入棧中,而後再將數據按照相反的順序從棧中取出。也就是說,先放入的數據最後才能取出,而最後放入的數據必須先取出。這稱爲先進後出(First In Last Out)原則。
棧的大小以及棧溢出
對每一個程序來講,棧能使用的內存是有限的,通常是1M~8M,在程序編譯時已經決定,運行期間不能改變,若是程序使用的棧超出最大值,就會發生棧溢出錯誤。
一個程序可能包含多個線程,每一個線程都有本身的棧,因此嚴格來講,最大值是針對線程來講的。
棧的大小是編譯器決定的,咱們能夠經過對編譯器設置來調整棧的大小。
棧溢出攻擊原理
C語言不會對數組溢出作檢測,數組溢出致使覆蓋了函數返回地址的例子,咱們將這樣的錯誤稱爲「棧溢出錯誤」。
8.c語言動態內存分配
在進程的地址空間中,代碼區、常量區、全局數據區的內存在程序啓動時就已經分配好了,它們大小固定,不能由程序員分配和釋放,只能等到程序運行結束由操做系統回收。這稱爲靜態內存分配。