一個程序的可執行文件在內存中的結果,從大的角度能夠分爲兩個部分:只讀部分和可讀寫部分。只讀部分包括程序代碼(.text)和程序中的常量(.rodata)。
可讀寫部分(變量)大體可分爲下面幾個部分:程序員
.data
:初始化了的全局變量和靜態變量.bss
:即 Block Started by Symbol
,未初始化的全局變量和靜態變量heap
:堆,使用 malloc
、realloc
和free
函數控制的變量,堆在全部的線程,共享庫,和動態加載的模塊中被共享使用。stack
:棧,函數調用時使用棧來保存函數現場,自動變量(即生命週期限制在某個 scope 的變量)也存放在棧中。.data
和 .bss
區這兩個常常放在一塊兒說,由於他們都是用來存儲全局變量和靜態變量的,區別在於 .data
區存放的初始化過的,.bss
區存放的是沒有初始化過的。例如:算法
int val = 3; char string[] = 'Hello World';
這兩個變量的值會在一開始被存儲在 .text
中,由於值是寫在代碼裏面的,在程序啓動時會拷貝到 .data
區中。
若不初始化,相似:segmentfault
static int i;
這個變量就會被放在 .bss
區中。安全
在一個代碼文件中,一個變量要麼定義在函數中,要麼定義在函數外。當定義在函數外時,這個變量就有了全局做用域,成爲了全局變量。
全局變量不光意味着這個變量能夠在整個文件中使用,也意味着這個變量能夠在其餘文件中使用(這種叫 external linkage
)。
當有以下兩個文件時:
A.c微信
#include <stdio.h> int a; int compute(void); int main() { a = 1; printf("%d %d", a, compute()); return 0; }
B.c數據結構
int a; int compute(void) { a = 0; return a; }
在編譯過程當中會產生重複定義的錯誤!由於有兩個全局的 a 變量,編譯器不知道應該使用哪個,爲了不這種問題,就須要引入 static
。函數
使用 static
關鍵字修飾的變量,static
關鍵字對變量的做用域進行了限制,具體的限制以下:性能
C++
在類中定義:全局變量,可是隻在此類中可見對於全局變量來講,爲了不上面提到的重複定義錯誤,咱們能夠在一個文件中使用 static
,另外一個不使用,這樣使用 static
的就會使用本身的 a 變量,而沒有用 static
的會使用全局的 a 變量。編碼
注意:靜態
這個中文翻譯有點莫名其妙,給人的感受像是不可改變的,實際上static
跟不可改變沒有關係,不可改變的變量使用 const
關鍵字修飾!!!spa
extern
extern
是 C 語言的另外一個關鍵字,用來指示變量或函數的定義在別的文件中,使用 extern
能夠在多個源文件中共享某個變量。
這裏提到的四個區,是指程序在內存中存在的形式,和程序在硬盤上存儲的格式不是徹底對應的。程序在硬盤上存儲的格式更加複雜,並且是和操做系統有關的,具體能夠參考:wikipedia。
一個明顯的例子區分這個差異:
以前提到的未定義的全局變量存儲在 .bss
區,這個區域不會佔用可執行文件的空間(通常只存儲這個區域的長度),可是卻會佔用內存空間。這些變量沒有定義,所以可執行文件中不須要存儲他們的值,在程序啓動過程當中,他們的值會被初始化成 0,存儲在內存中。
棧是用於存放本地變量,內部臨時變量以及有關上下文的內存區域。程序在調用函數時,操做系統會自動經過壓棧和彈棧完成保存函數現場等操做,不須要程序員手動干預。
棧是一塊連續的內存區域,棧頂的地址和棧的最大容量是系統預先規定好的,能從棧得到的空間較小。若是申請的空間超過棧的剩餘空間時,例如遞歸深度過深,將提示:stackoverflow
。
棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧、出棧都有專門的指令執行,這就決定了棧的效率比較高。
堆是用於存放除了棧裏的東西以外全部其餘東西的內存區域,當使用 malloc
和 free
時就是在操做堆中的內存。對於堆來講,釋放工做由程序員控制,容易產生 memory leak
。
堆是向高地址擴展的數據結構,是不連續的內存區域。這裏因爲系統是用鏈表來存儲的空閒內存地址的,天然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。因而可知,堆得到的空間比較靈活,也比較大。
對於堆而言,頻繁的 new
/delete
勢必會形成內存空間的不連續,從而形成大量的碎片,使程序效率下降。對於棧而言,則不會出現這個問題,由於棧是先進後出的隊列,永遠都不可能有一個內存塊從棧中間彈出。
堆都是動態分配的,沒有靜態分配的堆。棧有兩種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,好比局部變量的分配。動態分配由 alloca
函數進行分配,可是棧的動態分配和堆是不一樣的,他的動態分配是由編譯器進行釋放,無需咱們手工實現。
計算機底層並無對堆的支持,堆則是 C/C++ 函數庫提供的,同時因爲上面提到的碎片問題,都會致使堆的效率比棧要低。
虛擬地址先通過分段機制映射到線性地址,而後線性地址經過分頁機制映射到物理地址。
也成爲按需調頁,即對不在內存中的「頁」,當進程執行時才調入,不然有可能到程序結束時也不會調入。
Clock
算法。頁面的頻繁更換,致使整個系統效率急劇降低,這個現象稱爲內存抖動(或顛簸)。
抖動通常是內存分配算法很差,內存過小引發或者程序的算法不佳引發的。
Belady
現象對有的頁面置換算法,頁錯誤率可能會隨着分配幀數的增長而增長。
FIFO 會產生 Belady
異常。
棧式算法無 Belady
異常,LRU、LFU(最不常用)、OPT 都屬於棧式算法。
磁盤訪問延遲 = 隊列時間 + 控制器時間 + 尋道時間 + 旋轉時間 + 傳輸時間。
磁盤調度的目的是減少延遲,其中前兩項能夠忽略,尋道時間是主要矛盾。
Circular(環)
的意思。獨立硬盤冗餘陣列(RAID, Redundant Array of Independent Disks),舊稱廉價磁盤冗餘陣列(Redundant Array of Inexpensive Disks),簡稱磁盤陣列。利用虛擬化存儲技術把多個硬盤組合起來,成爲一個或多個硬盤陣列組,目的爲提高性能或數據冗餘,或是二者同時提高。
在運做中,取決於 RAID 層級不一樣,數據會以多種模式分散於各個硬盤,RAID 層級的命名會以 RAID 開頭並帶數字,例如:RAID 0、RAID 一、RAID 五、RAID 六、RAID 七、RAID 0一、RAID 十、RAID 50、RAID 60。每種等級都有其理論上的優缺點,不一樣的等級在兩個目標間獲取平衡,分別是增長數據可靠性以及增長存儲器(羣)讀寫性能。
Size = min(S1, S2, S3 ... Sn)
RAID 二、三、4 在實際應用中不多使用
Size = (N - 1) * min(S1, S2, S3... SN)
Size = (N - 2) * min(S1, S2, S3 ... SN)
一個沒有雞湯只有乾貨的公衆號