Linux系統相關的基礎問題(空間、內存、庫、鏈接、環境變量)

一、用戶空間與內核空間

1、用戶空間與內核空間

  4G的進程地址空間被人爲的分爲兩個部分–用戶空間與內核空間。用戶空間從0到3G(0xc0000000),內核空間佔據3G到4G。用戶進程通常情況下只能訪問用戶空間的虛擬地址,不能訪問內核空間的虛擬地址。例外情況只有用戶進程進行系統調用(代表用戶進程在內核態執行)等時刻可以訪問到內核空間。
這裏寫圖片描述

2、用戶態與內核態

  內核態: CPU可以訪問內存所有數據, 包括外圍設備, 例如硬盤, 網卡. CPU也可以將自己從一個程序切換到另一個程序。
  用戶態: 只能受限的訪問內存, 且不允許訪問外圍設備. 佔用CPU的能力被剝奪, CPU資源可以被其他程序獲取。

  爲什麼要有用戶態和內核態:

  由於需要限制不同的程序之間的訪問能力, 防止他們獲取別的程序的內存數據, 或者獲取外圍設備的數據, 併發送到網絡, CPU劃分出兩個權限等級 – 用戶態 和 內核態。所有用戶程序都是運行在用戶態的, 但是有時候程序確實需要做一些內核態的事情, 例如從硬盤讀取數據, 或者從鍵盤獲取輸入等. 而唯一可以做這些事情的就是操作系統, 所以此時程序就需要先操作系統請求以程序的名義來執行這些操作.。

二、物理內存(地址)與虛擬內存(地址)

1、早期的內存實現

(1)在早期的計算機中,運行一個程序的特點:

  • 把這些程序全都裝入內存;
  • 程序都是直接運行在內存上的,也就是說程序中訪問的內存地址都是實際的物理內存地址。

(2)在早期的內存實現方式中出現的問題:

  • 當計算 機同時運行多個程序時,必須保證這些程序用到的內存總量要小於計算機實際物理內存的大小;
  • 進程地址空間不隔離,進程間可以相互修改數據;
  • 內存使用率低。運行一個進程,必須在內存中爲它分配實際進程大小的空間(不管當前這些空間是否都會用到);
  • 程序運行的地址不確定。分配內存時,只是單純的從內存空間找一個足夠滿足進程要求的空間,所以進程運行的地址具有隨機性。

2、虛擬地址技術

  爲了解決上面的問題,一些大牛們就提出了傳說中的虛地址技術。即:在用戶進程和實際的物理內存之間加一箇中間層(虛擬地址),讓用戶進程只能訪問虛擬地址,並且把虛擬地址物理地址轉換的實現交給操作系統

(1)虛擬地址的特點:

  • OS會爲每個進程分配一個4G大小的虛擬地址空間,且每個進程都有3G的用戶空間和1G的內核空間。但最後這1G的內核空間中的內容對於不同進程來說是一樣的(之所以是4G大小,是因爲在32位操作系統中,一個指針的大小是4btyes,所以能訪問的地址空間就是0x00000000~0xFFFFFFFF == 4G);
  • 這4G的虛擬地址空間是操作系統虛擬出來的,並不是真實存在的,每次訪問內存空間的某個地址,都需要把地址翻譯爲實際物理內存地址。
  • 每個進程只能訪問自己的虛擬地址,無法訪問別的進程的虛擬地址;
  • 雖然每個進程的虛擬地址都有4G大小,但並不是這4G的地址都可以由用戶任意使用。
    這裏寫圖片描述

3、物理內存

  當打開程序時,系統會將這些程序加載到物理內存上。
這裏寫圖片描述

4、物理內存與虛擬內存的關係

  當運行程序過多,物理內存不夠用時,系統會將一部分硬盤空間當內存使用,這部分空間就是虛擬內存(主要是解決物理內存稀缺問題)。系統爲每個進程所分配的4GB虛擬地址空間(32位系統),用來存放進程的虛擬地址,進程直接操作虛擬地址空間,讀寫數據時,纔給它調撥物理存儲器(通過MMU(內存管理單元)將虛擬地址映射到物理內存地址)。

三、靜態庫與共享庫(動態庫)

  本質上來說庫是一種可執行代碼的二進制形式,可以被操作系統載入內存執行。由於Windows和linux本質不同,因此二者庫的二進制是不兼容的。庫有兩種:靜態庫(.a、.lib)和共享庫也稱動態庫(.so、.dll)。

1、靜態庫

  靜態庫將所有相關的目標文件打包成爲一個單獨的文件,即靜態庫文件,其缺省擴展名是 .a 。鏈接靜態庫就是將庫中被調用的代碼複製到調用模塊中。靜態庫佔用空間大,庫中代碼一旦修改必須重新鏈接。使用靜態庫的代碼在運行時無需依賴庫,且執行效率高

  靜態庫命名規範,必須是lib[your_library_name].a:lib爲前綴,中間是靜態庫名,擴展名爲.a。例如:libadd.a。

2、共享庫(動態庫)

  共享庫和靜態庫最大的不同就是,鏈接共享庫並不需要將庫中被調用的代碼複製到調用模塊中,相反被嵌入到調用模塊中的僅僅是被調用代碼在共享庫中的相對地址。如果共享庫中的代碼同時爲多個進程所用,共享庫的實例在整個內存空間中僅需一份,這正是共享的意義所在。共享庫佔用空間小,即使修改了庫中的代碼,只要接口保持不變,無需重新鏈接。使用共享庫的代碼在運行時需要依賴庫,執行效率略低。而共享庫的缺省擴展名是: .so。
  共享庫命名規範,必須是lib[your_library_name].so:lib爲前綴,中間是共享庫名,擴展名爲 .so
例如:libadd.so

3、共享庫(動態庫)與靜態庫的比較

(1)靜態庫在程序編譯時會被連接到目標代碼中,程序運行時將不再需要該靜態庫。當程序與靜態庫連接時,庫中目標文件所含的所有將被程序使用的函數的機器碼被copy到最終的可執行文件中。這就會導致最終生成的可執行代碼量相對變多,相當於編譯器將代碼補充完整了,這樣運行起來相對就快些。不過會有個缺點: 佔用磁盤和內存空間。靜態庫會被添加到和它連接的每個程序中,而且這些程序運行時,都會被加載到內存中,無形中又多消耗了更多的內存空間。

(2)動態庫在程序編譯時並不會被連接到目標代碼中,而是在程序運行是才被載入,因此在程序運行時還需要動態庫存在。與共享庫連接的可執行文件只包含它需要的函數的引用表,而不是所有的函數代碼,只有在程序執行時,那些需要的函數代碼才被拷貝到內存中。這樣就使可執行文件比較小,節省磁盤空間,更進一步,操作系統使用虛擬內存,使得一份共享庫駐留在內存中被多個程序使用,也同時節約了內存。不過由於運行時要去鏈接庫會花費一定的時間,執行速度相對會慢一些。

(3)總的來說靜態庫是犧牲了空間效率,換取了時間效率,共享庫是犧牲了時間效率換取了空間效率,沒有好與壞的區別,只看具體需要了

(4)另外,一個程序編好後,有時需要做一些修改和優化,如果我們要修改的剛好是庫函數的話,在接口不變的前提下,使用共享庫的程序只需要將共享庫重新編譯就可以了,而使用靜態庫的程序則需要將靜態庫重新編譯好後,將程序再重新編譯一遍

四、硬鏈接與軟鏈接

1、什麼是鏈接?

  鏈接簡單說實際上是一種文件共享的方式,是 POSIX 中的概念,主流文件系統都支持鏈接文件。

2、鏈接有什麼用

  你可以將鏈接簡單地理解爲 Windows 中常見的快捷方式(或是 OS X 中的替身),Linux 中常用它來解決一些庫版本的問題,通常也會將一些目錄層次較深的文件鏈接到一個更易訪問的目錄中。在這些用途上,我們通常會使用到軟鏈接(也稱符號鏈接)。

3、硬鏈接

  硬鏈接本質上是一個指針,指向目標文件的索引節點。一個目錄項只能對應一個索引節點,而一個索引節點可以對應多個目錄項。因此,一個目錄項只能有一個鏈接,而一個索引節點可以有多個鏈接。

4、軟鏈接

  軟鏈接是指一個文件的間接指針,其文件內容主要是用於記錄文件的存儲路徑。軟鏈接提供了一個指向目標文件的快捷途徑。

5、硬鏈接與軟鏈接的區別

  硬連接的作用是允許一個文件擁有多個有效路徑名,這樣用戶就可以建立硬連接到重要文件,以防止“誤刪”的功能。而建立軟鏈接就是建立了一個新文件。當訪問鏈接文件時,系統就會發現他是個鏈接文件,它讀取鏈接文件找到真正要訪問的文件

五、環境變量

  環境變量一般是指在操作系統中用來指定操作系統運行環境的一些參數,如:臨時文件夾位置和系統文件夾位置等。環境變量時在操作系統中一個具有特定名字的對象,它包含了一個或者多個應用程序所將使用的信息。

  linux是一個多用戶的操作系統,每個用戶登錄系統之後,都會有一個專用的運行環境。通常每個用戶默認的環境都是相同的。這個默認的環境實際上就是一組環境變量的定義,用戶可以對自己的運行環境進行定製,其方法就是修改相應的系統環境變量。

修改和查看環境變量的指令:

//echo:查看單個環境變量
# echo $HOME
/root

// env:查看所有環境變量
# env

// export:設置一個新的環境變量 (臨時的,重啓後消失)
# export HELLO="hello"
# echo $HELLO
hello

// unset:清除環境變量
# unset HELLO

// 添加環境變量
vim /etc/profile
添加 export PATH="/opt/hisi-linux/x86-arm/arm-hisiv300-linux/target/bin:$PATH"
執行 source /etc/profile

參考:https://www.cnblogs.com/zemliu/p/3695503.html
https://www.cnblogs.com/wuchanming/p/4465188.html
https://blog.csdn.net/qq_29350001/article/details/62217915

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章