乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      內(nèi)存管理基礎(chǔ)

       昵稱11935121 2018-04-20

      內(nèi)存管理基礎(chǔ)

      程序可執(zhí)行文件的結(jié)構(gòu)

      一個程序的可執(zhí)行文件在內(nèi)存中的結(jié)果,從大的角度可以分為兩個部分:只讀部分和可讀寫部分。只讀部分包括程序代碼(.text)和程序中的常量(.rodata)??勺x寫部分(也就是變量)大致可以分成下面幾個部分:

      • .data: 初始化了的全局變量和靜態(tài)變量

      • .bss: 即 Block Started by Symbol, 未初始化的全局變量和靜態(tài)變量(這個我感覺上課真的沒講過啊我去。。。)

      • heap: 堆,使用 malloc, realloc, 和 free 函數(shù)控制的變量,堆在所有的線程,共享庫,和動態(tài)加載的模塊中被共享使用

      • stack: 棧,函數(shù)調(diào)用時使用棧來保存函數(shù)現(xiàn)場,自動變量(即生命周期限制在某個 scope 的變量)也存放在棧中。

      下面就各個分區(qū)具體解釋一下:

      data 和 bss 區(qū)

      這兩個區(qū)經(jīng)常放在一起說,因?yàn)樗麄兌际怯脕泶鎯θ肿兞亢挽o態(tài)變量的,區(qū)別在于 data 區(qū)存放的是初始化過的, bss 區(qū)存放的是沒有初始化過的,例如:

      int val = 3;char string[] = 'Hello World';

      這兩個變量的值會一開始被存儲在 .text 中(因?yàn)橹凳菍懺诖a里面的),在程序啟動時會拷貝到 .data 去區(qū)中。

      而不初始化的話,像下面這樣:

      static int i;

      這個變量就會被放在 bss 區(qū)中。

      答疑一 靜態(tài)變量和全局變量

      這兩個概念都是很常見的概念,又經(jīng)常在一起使用,很容易造成混淆。

      全局變量:在一個代碼文件(具體說應(yīng)該一個 translation unit/compilation unit))當(dāng)中,一個變量要么定義在函數(shù)中,要么定義在在函數(shù)外面。當(dāng)定義在函數(shù)外面時,這個變量就有了全局作用域,成為了全局變量。全局變量不光意味著這個變量可以在整個文件中使用,也意味著這個變量可以在其他文件中使用(這種叫做 external linkage)。當(dāng)有如下兩個文件時;

      a.c

      #include int a;int compute(void);int main(){ a = 1; printf('%d %d\n', a, compute()); return 0;}

      b.c

      int a;int compute(void){ a = 0; return a;}

      在 Link 過程中會產(chǎn)生重復(fù)定義錯誤,因?yàn)橛袃蓚€全局的 a 變量,Linker 不知道應(yīng)該使用哪一個。為了避免這種情況,就需要引入 static。

      靜態(tài)變量: 指使用 static 關(guān)鍵字修飾的變量,static 關(guān)鍵字對變量的作用域進(jìn)行了限制,具體的限制如下:

      • 在函數(shù)外定義:全局變量,但是只在當(dāng)前文件中可見(叫做 internal linkage)

      • 在函數(shù)內(nèi)定義:全局變量,但是只在此函數(shù)內(nèi)可見(同時,在多次函數(shù)調(diào)用中,變量的值不會丟失)

      • (C++)在類中定義:全局變量,但是只在此類中可見

      對于全局變量來說,為了避免上面提到的重復(fù)定義錯誤,我們可以在一個文件中使用 static,另一個不使用。這樣使用 static 的就會使用自己的

      a 變量,而沒有用 static 的會使用全局的 a 變量。當(dāng)然,最好兩個都使用 static,避免更多可能的命名沖突。

      注意:'靜態(tài)'這個中文翻譯實(shí)在是有些莫名其妙,給人的感覺像是不可改變的,而實(shí)際上 static 跟不可改變沒有關(guān)系,不可改變的變量使用 const 關(guān)鍵字修飾,注意不要混淆。

      Bonus 部分 —— extern: extern 是 C 語言中另一個關(guān)鍵字,用來指示變量或函數(shù)的定義在別的文件中,使用 extern 可以在多個源文件中共享某個變量,例如這里的例子。 extern 跟 static 在含義上是“水火不容”的,一個表示不能在別的地方用,一個表示要去別的地方找。如果同時使用的話,有兩種情況,一種是先使用 static,后使用 extern ,即:

      static int m;extern int m;

      這種情況,后面的 m 實(shí)際上就是前面的 m 。如果反過來:

      extern int m;static int m;

      這種情況的行為是未定義的,編譯器也會給出警告。

      答疑二 程序在內(nèi)存和硬盤上不同的存在形式

      這里我們提到的幾個區(qū),是指程序在內(nèi)存中的存在形式。和程序在硬盤上存儲的格式不是完全對應(yīng)的。程序在硬盤上存儲的格式更加復(fù)雜,而且是和操作系統(tǒng)有關(guān)的,具體可以參考這里。一個比較明顯的例子可以幫你區(qū)分這個差別:之前我們提到過未定義的全局變量存儲在 .bss 區(qū),這個區(qū)域不會占用可執(zhí)行文件的空間(一般只存儲這個區(qū)域的長度),但是卻會占用內(nèi)存空間。這些變量沒有定義,因此可執(zhí)行文件中不需要存儲(也不知道)它們的值,在程序啟動過程中,它們的值會被初始化成 0 ,存儲在內(nèi)存中。

      棧是用于存放本地變量,內(nèi)部臨時變量以及有關(guān)上下文的內(nèi)存區(qū)域。程序在調(diào)用函數(shù)時,操作系統(tǒng)會自動通過壓棧和彈棧完成保存函數(shù)現(xiàn)場等操作,不需要程序員手動干預(yù)。

      棧是一塊連續(xù)的內(nèi)存區(qū)域,棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的。能從棧獲得的空間較小。如果申請的空間超過棧的剩余空間時,例如遞歸深度過深,將提示stackoverflow。

      棧是機(jī)器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計(jì)算機(jī)會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。

      堆是用于存放除了棧里的東西之外所有其他東西的內(nèi)存區(qū)域,當(dāng)使用malloc和free時就是在操作堆中的內(nèi)存。對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。

      堆是向高地址擴(kuò)展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計(jì)算機(jī)系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。

      對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因?yàn)闂J窍冗M(jìn)后出的隊(duì)列,永遠(yuǎn)都不可能有一個內(nèi)存塊從棧中間彈出。

      堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進(jìn)行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進(jìn)行釋放,無需我們手工實(shí)現(xiàn)。

      計(jì)算機(jī)底層并沒有對堆的支持,堆則是C/C++函數(shù)庫提供的,同時由于上面提到的碎片問題,都會導(dǎo)致堆的效率比棧要低。

      內(nèi)存分配

      • 虛擬地址:用戶編程時將代碼(或數(shù)據(jù))分成若干個段,每條代碼或每個數(shù)據(jù)的地址由段名稱 + 段內(nèi)相對地址構(gòu)成,這樣的程序地址稱為虛擬地址

      • 邏輯地址:虛擬地址中,段內(nèi)相對地址部分稱為邏輯地址

      • 物理地址:實(shí)際物理內(nèi)存中所看到的存儲地址稱為物理地址

      • 邏輯地址空間:在實(shí)際應(yīng)用中,將虛擬地址和邏輯地址經(jīng)常不加區(qū)分,通稱為邏輯地址。邏輯地址的集合稱為邏輯地址空間

      • 線性地址空間:CPU地址總線可以訪問的所有地址集合稱為線性地址空間

      • 物理地址空間:實(shí)際存在的可訪問的物理內(nèi)存地址集合稱為物理地址空間

      • MMU(Memery Management Unit內(nèi)存管理單元):實(shí)現(xiàn)將用戶程序的虛擬地址(邏輯地址) → 物理地址映射的CPU中的硬件電路

      • 基地址:在進(jìn)行地址映射時,經(jīng)常以段或頁為單位并以其最小地址(即起始地址)為基值來進(jìn)行計(jì)算

      • 偏移量:在以段或頁為單位進(jìn)行地址映射時,相對于基地址的地址值

      虛擬地址先經(jīng)過分段機(jī)制映射到線性地址,然后線性地址通過分頁機(jī)制映射到物理地址。

      虛擬內(nèi)存

      • 請求調(diào)頁,也稱按需調(diào)頁,即對不在內(nèi)存中的“頁”,當(dāng)進(jìn)程執(zhí)行時要用時才調(diào)入,否則有可能到程序結(jié)束時也不會調(diào)入

      頁面置換算法

      • FIFO算法

        先入先出,即淘汰最早調(diào)入的頁面。

      • OPT(MIN)算法

        選未來最遠(yuǎn)將使用的頁淘汰,是一種最優(yōu)的方案,可以證明缺頁數(shù)最小。

        可惜,MIN需要知道將來發(fā)生的事,只能在理論中存在,實(shí)際不可應(yīng)用。

      • LRU(Least-Recently-Used)算法

        用過去的歷史預(yù)測將來,選最近最長時間沒有使用的頁淘汰(也稱最近最少使用)。

        LRU準(zhǔn)確實(shí)現(xiàn):計(jì)數(shù)器法,頁碼棧法。

        由于代價較高,通常不使用準(zhǔn)確實(shí)現(xiàn),而是采用近似實(shí)現(xiàn),例如Clock算法。

      內(nèi)存抖動現(xiàn)象:頁面的頻繁更換,導(dǎo)致整個系統(tǒng)效率急劇下降,這個現(xiàn)象稱為內(nèi)存抖動(或顛簸)。抖動一般是內(nèi)存分配算法不好,內(nèi)存太小引或者程序的算法不佳引起的。

      Belady現(xiàn)象:對有的頁面置換算法,頁錯誤率可能會隨著分配幀數(shù)增加而增加。

      FIFO會產(chǎn)生Belady異常。

      棧式算法無Belady異常,LRU,LFU(最不經(jīng)常使用),OPT都屬于棧式算法。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多