C語言和內存

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語言動態內存分配

在進程的地址空間中,代碼區、常量區、全局數據區的內存在程序啓動時就已經分配好了,它們大小固定,不能由程序員分配和釋放,只能等到程序運行結束由操做系統回收。這稱爲靜態內存分配

相關文章
相關標籤/搜索