【Linux學習】進程地址空間與寫時拷貝

文章目錄

  • Linux進程內存布局圖:
      • 內存布局的驗證
  • 進程地址空間
    • 寫時拷貝


Linux進程內存布局圖:

地址空間的范圍,在32位機器上是2^32比特位,也就是[0,4G]。
在這里插入圖片描述

內存布局的驗證

  • 代碼驗證內存布局: 驗證代碼:
   #include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>int init=10;int uninit;int main(){printf("code addr:%p\n",&main);printf("init addr:%p\n",&init);printf("uninit addr:%p\n",&uninit);char* heap = (char* )malloc(20);printf("heap addr:%p\n",heap);printf("stack addr:%p\n",&heap);return 0;                                                                                                                             }

運行結果及分析:根據下圖運行結果分析,驗證了上圖的內存分布。
在這里插入圖片描述

  • 驗證堆向上增長與棧向下增長:

驗證代碼:

    char* heap1 = (char* )malloc(20);char* heap2 = (char* )malloc(20);char* heap3 = (char* )malloc(20);char* heap4 = (char* )malloc(20);char* heap5 = (char* )malloc(20);printf("heap1 addr:%p\n",heap1);printf("heap2 addr:%p\n",heap2);printf("heap3 addr:%p\n",heap3);printf("heap4 addr:%p\n",heap4);printf("heap5 addr:%p\n",heap5);printf("stack1 addr:%p\n",&heap1);printf("stack2 addr:%p\n",&heap2);printf("stack3 addr:%p\n",&heap3);printf("stack4 addr:%p\n",&heap4);printf("stack5 addr:%p\n",&heap5);                                                                                                    

運行結果:堆向上增長,棧向下減小,與內存分布圖一樣。
結論:堆棧相對而生。

在這里插入圖片描述

  • 驗證命令行參數與環境變量:

驗證代碼:

   int main(int argc,char* argv[],char* env[]){for(int i = 0;argv[i];i++){printf("&argv[%d]:%p \n",i,argv+i);}for(int i = 0;env[i];i++){printf("&env[%d]:%p \n",i,env+i);}return 0;}

運行結果及分析:環境變量與命令行參數這兩張表(不是表指向的內容),比棧區大,其中,是先有命令行參數這張表,才有環境變量這張表。
在這里插入圖片描述

  • 驗證表指向的內容的地址存放:

    注意區分下面代碼與上面代碼的不同!
    驗證代碼:

   int main(int argc,char* argv[],char* env[]){for(int i = 0;argv[i];i++){printf("argv[%d]:%p \n",i,argv[i]);}for(int i = 0;env[i];i++){printf("env[%d]:%p \n",i,env[i]);}return 0;}

結果+分析:無論是表還是表指向的項目,都在棧上部的。
在這里插入圖片描述

  • 驗證靜態變量在內存分布中的位置:
    這里就不驗證了,直接得出結論:靜態變量是存放在初始化數據與未初始化數據之間的。靜態變量默認是會被初始化的,哪怕用戶定義出來沒有賦值,編譯器也會初始化。例如int 類型的靜態變量,會被編譯器初始化為0;

看看一個這樣的代碼
代碼:

   #include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>int g_val = 1000;int main(){pid_t id = fork();if(id==0){//子進程while(1){printf("child  pid:%d  ppid:%d  g_val=%d  &g_val:%p\n",getpid(),getppid(),g_val,&g_val);sleep(1);}}//父進程                                                                                                                              else{while(1){printf("father  pid:%d  ppid:%d  g_val=%d  &g_val:%p\n",getpid(),getppid(),g_val,&g_val);sleep(1);}}return 0;}

運行結果:符合我們預期的,數據本來就是父子進程共享的,除非要寫入,進程之間時具有獨立性的,寫入的時候需要寫時拷貝。
在這里插入圖片描述

奇怪的現象:

測試代碼:

   #include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<sys/types.h>int g_val = 1000;int main(){pid_t id = fork();if(id==0){//子進程int cnt = 0;while(1){printf("child  pid:%d  ppid:%d  g_val=%d  &g_val:%p\n",getpid(),getppid(),g_val,&g_val);sleep(1);cnt++;                                                                                                                            if(cnt==3){printf("child change g_val\n");g_val=2000;}}//父進程else{while(1){                                                                                                                                   printf("father  pid:%d  ppid:%d  g_val=%d  &g_val:%p\n",getpid(),getppid(),g_val,&g_val);sleep(1);}}return 0;}

運行結果+分析:奇怪的現象(如下圖):同一個變量,子進程嘗試對g_val進行寫入的時候,會進行寫時拷貝,但是為什么地址一樣,但是值卻不一樣呢?
在這里插入圖片描述

解釋上面的現象:

  1. 地址一樣卻值不一樣,所以這個地址肯定不是物理地址。
  2. 如果是物理地址,絕對不可能在一個地址中存放的內容不一樣。

這個地址叫做虛擬地址/線性地址。
結論:我們平時用到的語言的地址全部都不是物理地址,是虛擬地址。所以下面這個圖的空間排布的情況不是物理內存,它叫做進程地址空間。
在這里插入圖片描述

進程地址空間

每一個進程都有一個task_struct(PCB),PCB里面有該進程的進程地址空間,進程地址空間和內存之間是用一張表(叫做頁表:里面存放的是虛擬地址與物理地址)建立關系的,如下圖,頁表對應一個映射關系,是虛擬地址與物理地址之間的關系。根據虛擬地址可以找到對應的物理地址。下面的結構都是操作系統內部在維護的。

在這里插入圖片描述

  • 說明:上面的圖就足矣說名問題,同一個變量,地址相同,其實是虛擬地址相同,內容不同其實是被映射到了不同的物理地址!

其中,父進程創建子進程后,子進程也會有一個這樣的結構,也會有進程地址空間,頁表,并且父進程PCB的大部分屬性都會被子進程繼承下來,頁表也會被繼承下來(類似淺拷貝),這時父子進程都指向同一個物理內存。以上面的示例分析:當子進程嘗試對g_val進行修改時,操作系統會在內存中重新開一個空間,將修改后的值放在這個空間里,再改變頁表中g_val的虛擬地址對應的物理地址,注意:改的是物理地址,虛擬地址沒有改變,所以上面示例的結果打印出來的地址(虛擬地址)沒有改變。如下圖:
在這里插入圖片描述
根據上面的解釋,也能夠很好的解釋fork()返回值問題了!

什么是進程地址空間?

進程地址空間是數據結構,具體到進程中,是有特定的數據結構對象。
如下圖所示:在進程的PCB中,有一個指針,指向自己的進程地址空間,進程地址空間里面,包含一個結構體,結構體里面有很多start和end,劃分區域。

在這里插入圖片描述

為什么要有地址空間和頁表?

  1. 在進程看來,有了頁表,可以將物理內存從無徐變為有序,因為頁表是有序的。讓進程以統一的視角,看待內存;
  2. 將進程管理和內存管解耦合,進程管理與內存管理互不干擾。
  3. 地址空間+頁表是保護內存安全的重要手段(攔截非法:例如:野指針,越界問題)。

內存申請問題(malloc/new)

申請內存,本質是進程的地址空間中申請。
這樣:可以充分保證:

  1. 內存使用率,不會空轉。
  2. 提升new/malloc的速度。

寫時拷貝

  1. 為什么需要寫時拷貝?
    答:進程之間要做到獨立性。
  2. 創建子進程的時候,為什么不直接將父進程的代碼和數據拷貝一份給子進程呢?
    答:因為子進程并不是會對父進程的所有數據都要進行寫入操作,如果fork()創建子進程的時候,直接拷貝一份代碼和數據,會降低fork()的效率。
  3. 為什么是要拷貝呢,只開空間不拷貝行不行?
    答:因為子進程不一定是對這個數據直接進行覆蓋式的寫入,可以只是對該數據進行局部修改或則是基于之前的值進行操作。

如何做到寫時拷貝的?

前面所說的頁表,不只是有虛擬地址與物理地址的轉換的,還可以帶很多選項的,如下圖(介紹其中一個:權限):
下圖代碼字符串"hello Linux"是具有常屬性的,不能被修改,當我們嘗試去修改的時候,會報錯(運行報錯)。
是因為在頁表有權限,虛擬地址映射到物理地址的時候,會做權限審核,如下圖所示,當只有可讀權限,沒有修改的權限的時候,嘗試去修改,就會報錯。
在這里插入圖片描述

寫時拷貝的細節:

當要進行寫時拷貝的時候,會將父子進程頁表里大部分內容的映射權限設置為只讀權限,當父子進程任何一方要去進行嘗試寫入的時候,操作系統會進行判斷,如果是數據段,對數據進行寫入時合理的,就會引發缺頁中斷,操作系統會將權限改為讀寫,然后寫時拷貝后,再把頁表對應的條目改為讀寫。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/14121.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/14121.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/14121.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

linux系統安全加固

目錄 1、賬戶安全基本措施 1&#xff09;系統賬戶清理 2&#xff09;密碼安全控制 3&#xff09;命令歷史限制 2、用戶切換及提權 1&#xff09;使用 su命令切換用戶 2&#xff09;使用sudo機制提升權限 3、系統引導和安全登錄控制 1&#xff09;開機安全控制 2&…

頭歌實踐教學平臺:Junit實訓入門篇

第2關&#xff1a;Junit注解 任務描述 給出一個帶有注解的Junit代碼及其代碼打印輸出&#xff0c;要求學員修改注解位置&#xff0c;讓輸出結果變為逆序。 相關知識 Junit注解 Java注解&#xff08;(Annotation&#xff09;的使用方法是" 注解名" 。借助注解&a…

python數據處理與分析入門-Pandas數據可視化例子

相關內容 Matplotlib可視化練習 Pandas 數據可視化總結 柱狀圖 reviews[points].value_counts().sort_index().plot.bar()散點圖 reviews[reviews[price] < 100].sample(100).plot.scatter(xprice, ypoints)蜂窩圖 reviews[reviews[price] < 100].plot.hexbin(xprice…

Helm安裝kafka3.7.0無持久化(KRaft 模式集群)

文章目錄 2.1 Chart包方式安裝kafka集群 5.開始安裝2.2 命令行方式安裝kafka集群 搭建 Kafka-UI三、kafka集群測試3.1 方式一3.2 方式二 四、kafka集群擴容4.1 方式一4.2 方式二 五、kafka集群刪除 參考文檔 [Helm實踐---安裝kafka集群 - 知乎 (zhihu.com)](https://zhuanlan.…

virtualbox共享文件夾沒有訪問權限

設置好共享文件夾之后&#xff0c;進入虛擬機&#xff0c;共享文件夾的地址是/media/sf_shared。 想要使用cd命令進入該文件夾時&#xff0c;你可能會發現此文件夾無法訪問&#xff0c;系統提示的原因是權限不足。 在虛擬機下查看共享文件夾的屬性&#xff0c;發現該目錄的所…

Nginx - 健康檢查終極指南:探索Upstream Check模塊

文章目錄 概述upstream_check_module模塊安裝和配置指南模塊安裝步驟基本配置示例詳細配置說明檢查類型和參數常見問題及解決方案 SSL檢查和DNS解析功能SSL檢查配置示例和說明配置示例 DNS解析配置示例和說明配置示例 結合實際應用場景的高級配置示例綜合SSL檢查與DNS解析 總結…

Doris【部署 03】Linux環境Doris數據庫部署異常問題收集解決(不斷更新)

Linux環境Doris數據庫部署異常問題 1.FE1.1 Unknown system variable character_set_database1.2 notify new FE type transfer: UNKNOWN1.3 mysql_load_server_secure_path1.4 Only unique table could be updated1.5 too many filtered rows 2.BE2.1 Have not get FE Master …

python:大文件分批/塊導入數據庫方式記錄

一、問題背景 對于數據文件比較大的數據&#xff0c;一次性串聯sql進行入庫&#xff0c;往往會受到數據庫本身對sql長度的限制&#xff0c;從而需要分塊或者分批次&#xff0c;將大數據文件一點一點的進行入庫。特針對這種入庫方式&#xff0c;進行一個簡單記錄&#xff0c;各…

spring的控制反轉(IoC)容器作用是什么?

控制反轉&#xff08;Inversion of Control&#xff0c;IoC&#xff09;容器是一種強大的設計模式&#xff0c;在現代軟件開發&#xff0c;特別是在使用Spring框架等企業級Java應用中至關重要。IoC容器主要作用是管理應用程序中對象的生命周期和依賴關系。我會逐步解釋它的作用…

YOLOv8改進 | 主干網絡 | 增加網絡結構增強小目標檢測能力【獨家創新——附結構圖】

??????本專欄所有程序均經過測試,可成功執行?????? 在目標檢測領域內,盡管YOLO系列的算法傲視群雄,但在某些方面仍然存在改進的空間。在YOLOv8提取特征的時候,由于卷積的緣故,會導致很多信息的丟失。對于小目標來說更是如此,這樣將大幅度降低小目標的檢測能…

pinpoint服務監控

Pinpoint是一個開源的APM&#xff08;應用性能管理&#xff09;系統&#xff0c;主要用于監控和管理Java應用程序的性能。它提供了實時的性能指標、分布式追蹤和診斷等功能&#xff0c;幫助開發和運維快速定位和解決應用程序中的性能問題。 pinpoint其他部分不變&#xff0c;H…

正確可用--Notepad++批量轉換文件編碼為UTF8

參考了:Notepad批量轉換文件編碼為UTF8_怎么批量把ansi轉成utf8-CSDN博客??????https://blog.csdn.net/wangmy1988/article/details/118698647我參考了它的教程,但是py腳本寫的不對. 只能改一個.不能實現批量更改. 他的操作步驟沒問題,就是把腳本代碼換成我這個. #-*-…

graspnet+Astra2相機實現部署

graspnetAstra2相機實現部署 &#x1f680; 環境配置 &#x1f680; ubuntu 20.04Astra2相機cuda 11.0.1cudnn v8.9.7python 3.8.19pytorch 1.7.0numpy 1.23.5 1. graspnet的復現 具體的復現流程可以參考這篇文章&#xff1a;Ubuntu20.04下GraspNet復現流程 這里就不再詳細…

數據庫系統概論(第5版)復習筆記

筆記的Github倉庫地址 &#x1f446;這是筆記的gihub倉庫&#xff0c;內容是PDF格式。 因為圖片和代碼塊太多&#xff0c;放到CSDN太麻煩了&#xff08;比較懶&#x1f923;&#xff09; 如果感覺對各位有幫助的話歡迎點一個?\^o^/

41-4 DDOS攻擊防護實戰

一、UDP FLOOD攻擊 # hping3 -q -n -a <攻擊IP> -S -s <源端口> --keep -p <目的端口> --flood <被攻擊IP> hping3 --udp -s 6666 -p 53 -a 192.168.1.6 --flood 192.168.1.13 這個命令是使用hping3工具進行UDP Flood攻擊的命令。下面是各個選項的作…

three.js能實現啥效果?看過來,這里都是它的菜(06)

這是第五期了&#xff0c;本期繼續分享three.js可以實現的3D動畫案例&#xff0c;有老鐵反饋再發案例的時候&#xff0c;是否可以順道分享一下three.js的知識點&#xff0c;好吧&#xff0c;安排。 材質動畫 材質動畫可以實現各種復雜的視覺效果&#xff0c;包括但不限于以下…

【css】引入背景圖時候,路徑寫入@會報錯

看報錯信息 我的寫法 解決辦法 在前面加個~

js解決數字小數計算出現的精度丟失問題(2024-05-24)

精度丟失的原因 js小數進行數值運算時出現精度丟失問題 JavaScript 的number類型在進行運算時都先將十進制轉二進制&#xff0c;此時&#xff0c;小數點后面的數字轉二進制時會出現無限循環的問題。 為了避免這一個情況&#xff0c;要舍0進1&#xff0c;此時就會導致精度丟失…

企業寬帶跑pcdn會被查嗎?

企業寬帶使用PCDN技術&#xff0c;本身并不違反相關規定&#xff0c;因此一般不會被查。PCDN是一種內容分發網絡技術&#xff0c;通過將內容緩存在離用戶更近的服務器上&#xff0c;減少數據傳輸的延遲&#xff0c;提高訪問速度。這種技術可以提高網頁加載速度和視頻播放流暢度…

Excel未響應時強關后,Excel插件消失

目錄 我們分析一下插件消失的原因&#xff1a; 針對上面表現出來的2個問題&#xff0c;進行針對性的解決 &#xff1a; 1、不被關進去&#xff0c;是不是就沒有后續的一系列的問題了&#xff0c;各自安好 2、保留住自動加載的行為 PS&#xff1a;配置受信任的位置注冊列表…