最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux深入理解進程和文件及內(nèi)存管理問題

 更新時間:2025年03月20日 10:07:50   作者:s_little_monster_  
這篇文章主要介紹了Linux深入理解進程和文件及內(nèi)存管理問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

一、重談Linux下一切皆文件

我們說了一切皆文件,對于操作系統(tǒng)來說,磁盤鍵盤顯示屏等等一系列的外設都是文件。

舉一個訪問外設的例子:

進程運行,從進程PCB中找到指針指向文件管理結(jié)構(gòu)體,然后在這個結(jié)構(gòu)體中我們可以找到struct file*類型的指針指向一個個的文件管理結(jié)構(gòu)體struct file,在這些結(jié)構(gòu)體中都有著一個專門放讀寫函數(shù)的結(jié)構(gòu)體,調(diào)用這些讀寫函數(shù)可以訪問到外設存放讀寫函數(shù)的結(jié)構(gòu)體,而雖然每個外設的讀寫方式不同,但它們僅把處理好的代碼封裝后將接口漏出,方便上方函數(shù)的統(tǒng)一調(diào)用,這樣雖然每個外設不同,但是我們通過一種求同存異的方法,將它們統(tǒng)一協(xié)調(diào)調(diào)度起來

類似于鍵盤一類的只有讀或者顯示屏一類的只有寫的外設,我們也有讀或?qū)懙慕涌冢皇墙涌诓蛔鎏幚?,方便統(tǒng)一

二、操作系統(tǒng)對物理內(nèi)存的管理

1、物理內(nèi)存與磁盤的數(shù)據(jù)交互

在操作系統(tǒng)的運行機制里,物理內(nèi)存和磁盤之間的數(shù)據(jù)交換起著關(guān)鍵作用,這種交換一般就是以頁page為單位,常見的頁大小為 4KB,在物理內(nèi)存中,一個 4KB 大小的空間被稱作頁框,而從磁盤加載到這個頁框里的4KB數(shù)據(jù)塊則被叫做頁

采用這種以頁為單位進行數(shù)據(jù)交換的方式,具有顯著的優(yōu)勢,一方面,能有效減少IO操作的次數(shù),進而提升系統(tǒng)效率,舉例來說,如果需要讀取數(shù)據(jù),一次讀取 4KB 與分四次讀取每次 1KB 相比,前者的效率要高得多,對于硬盤來說,一次讀取 4KB 時,CPU 只需與磁盤進行一次交互,而分四次讀取 1KB 時,CPU 要與磁盤進行四次交互,且這四次操作很可能不連續(xù),這就意味著效率低下,另一方面,這種方式還遵循基于局部性原理的預加載機制,即便當前 CPU 僅需訪問 100 字節(jié)的內(nèi)容,操作系統(tǒng)和磁盤之間依舊會以 4KB 為單位將數(shù)據(jù)加載進來,這是因為根據(jù)經(jīng)驗,CPU 在訪問當前磁盤中的代碼和數(shù)據(jù)時,后續(xù)有較大概率會訪問附近空間的代碼和數(shù)據(jù),還有一方面,就是對齊,磁盤中的最小寫入單位是頁,因為計算機硬件的設計往往遵循一定的對齊規(guī)則,這樣可以提高數(shù)據(jù)訪問的效率內(nèi)存和磁盤控制器在設計時,通常會按照特定的字節(jié)邊界來組織和傳輸數(shù)據(jù),以頁為單位進行數(shù)據(jù)交換可以保證數(shù)據(jù)在內(nèi)存和磁盤之間的傳輸是按照硬件對齊要求進行的,減少硬件處理的復雜性

2、操作系統(tǒng)對物理內(nèi)存的管理

操作系統(tǒng)具備感知物理內(nèi)存的能力,其對物理內(nèi)存的管理遵循先描述再組織的原則,在內(nèi)核中,struct page 結(jié)構(gòu)體承擔著描述物理內(nèi)存的重要職責,一個 struct page 對象對應著一個 4KB 的內(nèi)存頁框,該結(jié)構(gòu)體中記錄了當前頁框的諸多屬性信息,像頁框的狀態(tài)、引用計數(shù)等

操作系統(tǒng)會把物理內(nèi)存劃分成一個個的struct page對象,再用數(shù)組的形式將它們組織起來,數(shù)組的下標即為對應的頁號,若要確定一個物理地址所在的頁號,只需將該物理地址除以 4096 b(4KB = 4 * 1024 = 4096 b),或者將該地址按位與上 0xFFFFF000(以 32 位系統(tǒng)為例),把低 12 位清零,得到的結(jié)果就是該地址所在的頁號

在進行內(nèi)存申請操作時,系統(tǒng)會訪問 page 數(shù)組,查看 struct page 里的 flags 屬性,通過這個屬性,系統(tǒng)能夠判斷當前頁框的狀態(tài),確定其是否已被使用,若未被使用,系統(tǒng)就會修改 flags 以表明該頁框已被申請,此外,flags 除了能表示頁框的使用狀態(tài)外,還能指示該頁框是只讀還是可讀寫等狀態(tài),

當然這里所介紹的只是操作系統(tǒng)對物理內(nèi)存管理的一個基礎(chǔ)模型,實際上真正的內(nèi)存管理系統(tǒng)要復雜得多

三、文件頁緩沖區(qū)

在操作系統(tǒng)內(nèi)核中,struct file 是一個重要的數(shù)據(jù)結(jié)構(gòu),用于描述一個已打開的文件,而 inode 這一概念是在介紹磁盤時引入的,磁盤上的每個文件都對應著一個inode,它存儲了該文件的屬性信息,struct fileinode 之間存在著緊密的聯(lián)系,struct file中僅記錄了文件的少量屬性,而struct inode結(jié)構(gòu)體則專門用于記錄一個文件的所有屬性,在 struct file 中有一個指針字段,它指向該文件的struct inode對象

文件由內(nèi)容和屬性兩部分構(gòu)成,在磁盤上,文件的屬性由 inode存儲,文件的內(nèi)容則由數(shù)據(jù)塊存儲,那么,在操作系統(tǒng)內(nèi)核中,文件的內(nèi)容(數(shù)據(jù))是如何表示的呢?答案就是通過文件頁緩沖區(qū),在 struct file 結(jié)構(gòu)中有一個指向 struct address_space 結(jié)構(gòu)體的指針,在 struct address_space 結(jié)構(gòu)體中,有一個 struct radix_tree_root 結(jié)構(gòu)體對象,它實際上是一種樹狀結(jié)構(gòu),即基數(shù)樹(也叫字典樹),樹中的每個節(jié)點都是 struct radix_tree_node 類型,該類型中有一個名為 slotsvoid* 類型數(shù)組,數(shù)組中存儲的其實就是 struct page 對象的地址,簡單來說,在 struct file 結(jié)構(gòu)體中有指向物理內(nèi)存頁框的指針,我們把這些物理內(nèi)存區(qū)域稱為文件頁緩沖區(qū)

向文件寫入數(shù)據(jù)的過程

當使用C/C++庫函數(shù)向文件中寫入數(shù)據(jù)時,整個過程分為幾個階段,首先,數(shù)據(jù)有可能會被寫入到語言層面的用戶緩沖區(qū),然后,在合適的時機,這些數(shù)據(jù)會被從用戶緩沖區(qū)寫入到該文件對應的文件頁緩沖區(qū)中,最后,還是在合適的時機,數(shù)據(jù)會從文件頁緩沖區(qū)被寫入到磁盤

將物理內(nèi)存中的數(shù)據(jù)刷新到磁盤這一操作由IO子系統(tǒng)負責執(zhí)行,進程通常無需關(guān)注具體的執(zhí)行過程,在操作系統(tǒng)中,會存在大量的IO操作,可能有很多進程都需要將數(shù)據(jù)寫入磁盤,為了有效管理這些操作,操作系統(tǒng)會按照先描述再組織的方式對所有的IO操作進行管理,內(nèi)核中的struct request結(jié)構(gòu)就是專門用來描述一個IO操作的

在Linux操作系統(tǒng)中,每個進程打開的每個文件都有自己的 struct inode 對象和對應的文件頁緩沖區(qū),也就是所謂的內(nèi)核緩沖區(qū),它們共同保障了文件操作的高效和穩(wěn)定

四、動態(tài)庫是如何被加載的

動態(tài)庫在進程運行時要被加載到內(nèi)存,一般我們常用的動態(tài)庫是要被所有的可執(zhí)行程序動態(tài)鏈接的,所以動態(tài)庫在系統(tǒng)中加載完成后,會被所有的進程所共享

在操作系統(tǒng)的進程管理與庫使用機制中,進程與動態(tài)庫的交互有著獨特的方式,一個進程在運行過程中,是可以同時鏈接多個動態(tài)庫的,不過,當系統(tǒng)中存在多個進程時,不能簡單地認為系統(tǒng)中必然存在多個不同的動態(tài)庫,多個進程可能會依賴相同的動態(tài)庫,操作系統(tǒng)對動態(tài)庫采用“先描述,再組織”的策略進行管理,它會為每個動態(tài)庫創(chuàng)建相應的數(shù)據(jù)結(jié)構(gòu)來描述其屬性、位置等信息,然后將這些描述信息組織起來,以便高效地進行查找、加載和管理,憑借這種管理方式,操作系統(tǒng)對系統(tǒng)中所有動態(tài)庫的加載狀態(tài)了如指掌

a.exe 為例,它在編譯鏈接階段選擇使用動態(tài)庫,當 a.exe 運行成為 a 進程后,CPU 會按照程序的指令順序依次執(zhí)行代碼,假設在執(zhí)行過程中遇到了一個庫函數(shù)調(diào)用,此時,操作系統(tǒng)會檢查該函數(shù)所在的動態(tài)庫是否已經(jīng)被加載到內(nèi)存中,若尚未加載,操作系統(tǒng)會負責將該動態(tài)庫加載到內(nèi)存,這一加載過程本質(zhì)上與文件加載一致,因為動態(tài)庫本身也是以文件形式存在的,并且具有 inode 來標識其在文件系統(tǒng)中的元數(shù)據(jù)

動態(tài)庫加載完成后,操作系統(tǒng)會在 a 進程的頁表中建立該動態(tài)庫與 a 進程地址空間中共享區(qū)的映射關(guān)系,這樣,當 CPU 需要執(zhí)行上述函數(shù)時,就可以從代碼段跳轉(zhuǎn)到共享區(qū)去執(zhí)行動態(tài)庫中該函數(shù)的代碼,執(zhí)行完畢后,CPU 會跳轉(zhuǎn)回代碼段,繼續(xù)執(zhí)行后續(xù)的程序指令

b.exe 同樣在編譯鏈接時采用動態(tài)庫,之后被加載到內(nèi)存成為 b 進程,當 CPU 執(zhí)行 b 進程的代碼并遇到上面函數(shù)調(diào)用時,因為在 a 進程已經(jīng)將該所在的動態(tài)庫加載到了內(nèi)存,操作系統(tǒng)不會再次重復加載該動態(tài)庫,而是直接在 b 進程的頁表中建立該動態(tài)庫與 b 進程共享區(qū)的映射關(guān)系,通過這種方式,同一個動態(tài)庫可以被多個進程共享使用,所以動態(tài)庫又被稱為共享庫

關(guān)于動態(tài)庫中的全局變量

動態(tài)庫確實可以被多個進程共享,但對于動態(tài)庫中的全局變量(例如 errno),需要特殊的處理機制來保證各個進程之間的數(shù)據(jù)獨立性,errno 是 C 語言標準庫提供的一個全局變量,用于存儲最近一次庫函數(shù)調(diào)用失敗時的錯誤碼

如果簡單地讓所有進程共享 errno,會引發(fā)嚴重的問題,例如,當 a 進程調(diào)用庫函數(shù)失敗,errno 被設置為 1,此時如果 b 進程也使用這個共享的 errno,就會導致 b 進程錯誤地獲取到 a 進程的錯誤碼,這顯然不符合邏輯

實際上,操作系統(tǒng)采用了寫時拷貝技術(shù)來解決這個問題,當某個進程要修改 errno 時,操作系統(tǒng)會通過引用計數(shù)來判斷該動態(tài)庫是否被多個進程共享,如果該動態(tài)庫被多個進程共享,操作系統(tǒng)會為該進程復制一份動態(tài)庫中相關(guān)數(shù)據(jù)(包括 errno)的副本,而不是直接修改共享的數(shù)據(jù),這樣,每個進程都有自己獨立的 errno 副本,從而保證了各個進程之間的錯誤碼不會相互干擾,只有當進程對數(shù)據(jù)進行寫操作時才會發(fā)生拷貝,而在只讀的情況下,多個進程仍然可以共享同一份動態(tài)庫數(shù)據(jù),從而充分發(fā)揮了動態(tài)庫共享的優(yōu)勢

五、深入理解地址

1、程序地址

在一個程序編譯好后形成了可執(zhí)行文件,在它的內(nèi)部是有地址的概念的,這里程序內(nèi)部的地址我們稱為邏輯地址,我們計算機一般采用的是平坦模式編址,平坦模式編址是一種簡化的內(nèi)存編址模型,在這種模式下,整個內(nèi)存空間被視為一個連續(xù)的、線性的地址空間,程序可以直接訪問這個連續(xù)地址空間內(nèi)的任意內(nèi)存位置,而不需要像分段模式那樣進行復雜的段地址和偏移地址組合計算,在平坦模式中,內(nèi)存地址是一個單一的、連續(xù)的數(shù)值,從 0 開始一直到系統(tǒng)所支持的最大內(nèi)存地址

32位下的4GB內(nèi)存地址

2、進程地址

我們知道,可執(zhí)行程序內(nèi)部采用的是邏輯地址(也叫虛擬地址)進行編址,物理內(nèi)存本身有其固定的物理地址,無論可執(zhí)行程序是否加載,物理內(nèi)存的地址體系是一直存在的,當可執(zhí)行程序被加載到內(nèi)存后,程序中的每一條指令和數(shù)據(jù)都會對應一個物理地址,這是通過地址映射機制實現(xiàn)的

那么,CPU 是如何知道可執(zhí)行程序的第一條指令位置呢?在編譯生成可執(zhí)行程序時,除了生成代碼段、數(shù)據(jù)段等程序內(nèi)容外,還會生成一個文件頭,這個文件頭包含了諸多重要信息,其中就有可執(zhí)行程序的入口地址,此地址是邏輯地址(虛擬地址)

在 CPU 中有一個關(guān)鍵的寄存器,即程序計數(shù)器—PC 寄存器,它存儲著接下來要執(zhí)行指令的地址,實際上,在程序啟動階段,不會立刻把整個可執(zhí)行程序加載到內(nèi)存(可以想象我們打游戲的時候不是打開游戲就能玩的,需要等待加載)而是先將可執(zhí)行文件的頭部加載進來,操作系統(tǒng)讀取文件頭,從中獲取可執(zhí)行程序的入口地址,并將該地址設置到 PC 寄存器中

CPU 拿到這個虛擬地址后,會借助內(nèi)存管理單元去查詢頁表,頁表記錄了虛擬地址和物理地址的映射關(guān)系,若查詢發(fā)現(xiàn)該虛擬地址對應的頁表項無效,也就是此頁面尚未建立內(nèi)存映射,操作系統(tǒng)會觸發(fā)缺頁中斷,缺頁中斷發(fā)生后,操作系統(tǒng)暫停當前程序的執(zhí)行,從磁盤把對應的程序頁面加載到物理內(nèi)存的空閑頁框中,同時更新頁表,建立起虛擬地址到物理地址的映射,之后,恢復程序執(zhí)行,CPU 就能訪問到物理內(nèi)存中對應的指令了

CPU 憑借其內(nèi)置的指令集,能夠明確識別每條指令的長度,在正常運行狀態(tài)下,CPU 按照 PC 寄存器所存儲的地址順序執(zhí)行指令,每執(zhí)行完一條指令,PC 寄存器會自動更新為下一條指令的地址,當程序執(zhí)行過程中遇到函數(shù)調(diào)用指令或跳轉(zhuǎn)指令時,PC 寄存器的值會被修改為新的虛擬地址,CPU 會依據(jù)這個新的虛擬地址再次查詢頁表,若發(fā)現(xiàn)頁面未在內(nèi)存中,將再次觸發(fā)缺頁中斷

由此可見,CPU 正是通過將虛擬地址轉(zhuǎn)換為物理地址的方式,來執(zhí)行可執(zhí)行程序中的指令以及訪問可執(zhí)行程序中的變量的,這種基于虛擬內(nèi)存和地址映射的機制,為程序提供了獨立的地址空間,增強了內(nèi)存管理的靈活性和安全性

3、動態(tài)庫地址

在計算機系統(tǒng)的程序執(zhí)行機制中,可執(zhí)行程序內(nèi)部采用邏輯地址進行編址,CPU通過將虛擬地址轉(zhuǎn)換為物理地址的方式來執(zhí)行指令

靜態(tài)庫在編譯鏈接過程中會被整合到可執(zhí)行文件中,當可執(zhí)行程序啟動運行時,操作系統(tǒng)會將包含靜態(tài)庫代碼的可執(zhí)行文件加載到物理內(nèi)存,之后 CPU 方可執(zhí)行其中的指令,靜態(tài)庫中的函數(shù)采用絕對編址,這是因為它們已成為可執(zhí)行文件的組成部分,其地址在編譯鏈接階段就已經(jīng)確定下來

在可執(zhí)行程序的編譯階段,對動態(tài)庫內(nèi)函數(shù)的引用表現(xiàn)為未解析的符號,當程序進入運行狀態(tài)時,動態(tài)鏈接器承擔起解析這些符號的任務,由于動態(tài)庫在運行時能夠被加載到虛擬內(nèi)存共享區(qū)的任意位置,要將動態(tài)庫加載到固定位置存在較大困難,這是由于一個可執(zhí)行程序往往會同時使用多個動態(tài)庫,各個動態(tài)庫的大小不盡相同,并且每個動態(tài)庫都采用獨立的編址方式,不同動態(tài)庫中可能出現(xiàn)相同的編址情況,為了實現(xiàn)動態(tài)庫在虛擬內(nèi)存共享區(qū)任意位置的加載,動態(tài)庫內(nèi)部采用相對編址的方法,對于動態(tài)庫中的函數(shù),僅需明確其在庫中的偏移量即可,鑒于庫中函數(shù)的偏移量是已知的(在編譯動態(tài)庫時,編譯器會按照一定的規(guī)則對庫中的代碼和數(shù)據(jù)進行布局,編譯器知道每個函數(shù)在代碼段中的起始位置以及函數(shù)內(nèi)部代碼的長度),動態(tài)庫便能夠被加載到虛擬內(nèi)存共享區(qū)的任意位置

在此機制下,操作系統(tǒng)只需記錄每個動態(tài)庫在虛擬內(nèi)存中的起始地址,當需要執(zhí)行某個動態(tài)庫函數(shù)時,通過將該函數(shù)所在動態(tài)庫的起始地址與該函數(shù)的偏移量相加,即可得到該函數(shù)在程序地址空間中的虛擬地址,隨后,依據(jù)此虛擬地址查詢頁表,找到該函數(shù)在物理內(nèi)存中的對應地址,進而執(zhí)行該庫函數(shù),GCC 編譯器中的 -fPIC 選項,其作用就是讓編譯器在生成動態(tài)庫文件時,直接使用偏移量對庫中的函數(shù)進行編址,從而實現(xiàn)代碼的位置無關(guān)性

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • linux輸入輸出重定向使用詳解

    linux輸入輸出重定向使用詳解

    linux中使用重定向符號可以實現(xiàn)輸出輸入重定向,默認條件下,標準輸出和錯誤輸出都是終端,用重定向符號可以把標準輸出和錯誤內(nèi)容進行重定向,例如把標準輸出重定向到文件,看下面的詳細解釋
    2014-01-01
  • Linux centos7如何查看目錄下的子目錄

    Linux centos7如何查看目錄下的子目錄

    這篇文章主要介紹了Linux centos7如何查看目錄下的子目錄問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Centos7中搭建Nginx環(huán)境全過程

    Centos7中搭建Nginx環(huán)境全過程

    本文詳細講述了在Linux上安裝并配置Nginx的過程,包括安裝依賴庫、解壓安裝包、編譯安裝Nginx等步驟,并提供了啟動、停止、重啟Nginx服務及配置Nginx常用命令的方法
    2026-04-04
  • linux命令:echo使用解讀

    linux命令:echo使用解讀

    這篇文章主要介紹了linux命令之關(guān)于echo的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • linux服務器上安裝Anaconda與pytorch的詳細過程

    linux服務器上安裝Anaconda與pytorch的詳細過程

    這篇文章主要介紹了linux服務器上安裝Anaconda與pytorch的詳細過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-10-10
  • windows下apache的簡單命令

    windows下apache的簡單命令

    這篇文章主要介紹了windows下apache的簡單命令,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Apache?Flink?如何保證?Exactly-Once?語義(其原理分析示例)

    Apache?Flink?如何保證?Exactly-Once?語義(其原理分析示例)

    Apache?Flink?是一個流處理和批處理的開源平臺,它提供了豐富的語義保證,其中之一就是?Exactly-Once?語義,本文將深入探討?Flink?是如何保證?Exactly-Once?語義的,包括其原理分析和相關(guān)示例,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • linux服務器下添加用戶和刪除用戶的命令

    linux服務器下添加用戶和刪除用戶的命令

    linux服務器下添加用戶和刪除用戶的命令,需要的朋友可以參考下。
    2011-11-11
  • Linux中查看指定文件夾內(nèi)各個子文件夾內(nèi)的文件數(shù)量

    Linux中查看指定文件夾內(nèi)各個子文件夾內(nèi)的文件數(shù)量

    今天小編就為大家分享一篇關(guān)于Linux中查看指定文件夾內(nèi)各個子文件夾內(nèi)的文件數(shù)量,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Centos系統(tǒng)中用mock構(gòu)建rpm的方法

    Centos系統(tǒng)中用mock構(gòu)建rpm的方法

    這篇文章主要給大家介紹了在Centos系統(tǒng)中用mock構(gòu)建rpm的方法,文中給出了詳細的命令代碼,相信對大家的理解和學習具有一定的參考借鑒家價值,有需要的朋友們下面來一起看看吧。
    2016-12-12

最新評論

外汇| 三穗县| 健康| 吉林市| 大化| 津市市| 灌南县| 平度市| 沙洋县| 朔州市| 辛集市| 子洲县| 田东县| 海阳市| 绥化市| 大化| 扶沟县| 炎陵县| 临澧县| 汝南县| 太仓市| 巴塘县| 景德镇市| 定南县| 沙田区| 会东县| 南汇区| 黄冈市| 石家庄市| 贵定县| 拜城县| 新兴县| 宣武区| 义乌市| 正阳县| 昭觉县| 吉木萨尔县| 横山县| 台南县| 榆中县| 榆林市|