Linux 程序地址空間

目錄

Ⅰ、什么是程序地址空間?

Ⅱ、虛擬地址空間是什么樣的?

一、虛擬地址空間和頁表

1、什么是頁表?

2、什么是虛擬地址空間?

3、什么是vm_area_struct?

Ⅲ、為什么要用虛擬地址空間?

一、進程的獨立性

二、保護數據安全

三、管理模塊和內存模塊的解耦合


Ⅰ、什么是程序地址空間?

在我們之前學習C語言/C++的時候可能我們看過下面圖片,當時有人告訴我們不同的數據和代碼存放在了內存的什么地方,當我們現在學習了操作系統了以后我們對這個圖片產生了一些疑問,我們我們在之前的博客說過進程的產生如果我們的內存是這樣排布的我們的進程應該怎么去存放?現在我們將提出虛擬地址空間也叫程序地址空間。

那什么是虛擬地址空間?

說的形象一點,假設操作系統是老板,進程是員工,那么虛擬地址空間就是老板給員工畫的大餅,操作系統告訴進程,這個內存里邊只有你和我在這里邊,你只要好好進行這里邊的內存全部是你的。這樣進程以為他可以擁有全部的內存。這就是虛擬地址空間。

下面我們來看一段代碼:

#include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>4 5 6 int num = 0;7 8 int main()9 {10     pid_t id = fork();11     if(id == 0)12     {13         //子進程14         num = 1;15         printf("我是一個子進程,num地址:%p, num = %d \n", &num , num);                                                                                                         16     }17     else18     {19 20         printf("我是一個父進程,num地址:%p, num = %d \n", &num , num);21     }22     return 0;23 }
~                                                                                                                                                                                   
~                                                                      

看上面這段代碼我們可以發現在同一個地址下不同的進程的值竟然是不一樣的,我們在之前的學習我們知道一個地址只能有一個值,這是為什么?這其實就是虛擬地址空間的作用下面我們來詳細了解虛擬地址空間。

Ⅱ、虛擬地址空間是什么樣的?

一、虛擬地址空間和頁表

我們先來解釋一下上文的問題,為什么一個地址父子進程的值卻不一樣?這時以為在操作系統創建進程的時候不僅僅是創建PCB,去創建虛擬地址空間和頁表,還要去加載代碼和數據。這樣一個進程才真正的被創建。

1、什么是頁表?

下面我們先來解釋頁表的功能:頁表可以把虛擬地址一一對應真實的物理地址。

我們上面說過虛擬程序地址就像操作系統給進程畫的一張大餅,操作系統告訴進程你可以把你的數據按照一定的順序放,進程把自己的代碼和數據按照不同的特性放在了不同的區域,但實際上內存中不止一個進程當然一個進程也不可能擁有一整塊內存,所以操作系統要靠一個東西把進程的代碼和數據在虛擬地址空間和物理空間一一對應這個東西就是頁表。

2、什么是虛擬地址空間?

虛擬地址空間被分為了很多部分,比如堆區,棧區,等等。那么如何去做區域劃分的呢?我們知道整個虛擬地址空間(假設是32位機器)被統一編址從0X00000000~0Xffffffff。如果我們可以記錄每個區域的起始和結束那么就可以實現了區域劃分,那么在操作系統內核中是如何做的呢?在Linux中用了一個內核數據結構來實現這個就是mm_struct。

struct mm_struct
{
struct vm_area_struct *mmap; /* 指向虛擬區間(VMA)鏈表 */
struct rb_root mm_rb; /* red_black樹 */
unsigned long task_size; /*具有該結構體的進程的虛擬地址空間的??*/
/*...*/
// 代碼段、數據段、堆棧段、參數段及環境段的起始和結束地址。
unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end;
}

3、什么是vm_area_struct?

我們知道在我們申請空間的時候是在堆上開空間,那么我們每次申請的空間都是不連續的那么mm_struct里只有兩個變量去區分堆的開始和結束,這里我們就有一個疑問:我們開的空間是不連續的但我們只有兩個變量去確定區間,也不能把每個空間的開始和結束都表示出來啊?

這個時候我們用vm_area_struct去解決這個問題

struct vm_area_struct {
unsigned long vm_start; //虛存區起始
unsigned long vm_end; //虛存區結束
struct vm_area_struct *vm_next, *vm_prev; //前后指針
struct rb_node vm_rb; //紅?樹中的位置
unsigned long rb_subtree_gap;
struct mm_struct *vm_mm; //所屬的 mm_struct
pgprot_t vm_page_prot;
unsigned long vm_flags; //標志位
struct {
struct rb_node rb;
unsigned long rb_subtree_last;
} shared;
struct list_head anon_vma_chain;
struct anon_vma *anon_vma;
const struct vm_operations_struct *vm_ops; //vma對應的實際操作
unsigned long vm_pgoff; //?件映射偏移量
struct file * vm_file; //映射的?件
void * vm_private_data; //私有數據
atomic_long_t swap_readahead_info;
#ifndef CONFIG_MMU
struct vm_region *vm_region; /* NOMMU mapping region */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *vm_policy; /* NUMA policy for the VMA */
#endif
struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
} __randomize_layout;

我們看上面的代碼我們可以看見start,end,next,prev,其實mm_struct中只記錄每個區域總的開始和結束而具體的每個空間(比如我們在堆上開辟的空間)的?開始和結束是由vm_area_struct記錄,然后將vm_area_struct再組織起來。

組織虛擬空間有兩種方式:

1、當虛擬區比較少的時候用單鏈表,mmap指向這個鏈表

2、當虛擬區比較多的用紅黑樹進行組織,mm_rb指向這顆紅黑樹

Ⅲ、為什么要用虛擬地址空間?

一、進程的獨立性

每個進程都有一個task_struct , mm_struct , vm_area_struct等相互獨立,頁表將虛擬地址和物理地址一一對應的,當創建子進程被創建的時候操作系統會先拷貝父進程的task_struct , mm_struct , vm_area_struct然后將一部分,比如pid,ppid等改變,最后交給子進程,當父進程或者子進程對數據進行改變的時候操作系統會進行寫時拷貝,重新開辟一個新的物理空間然后把數據拷貝進去再去改動,然后操作系統改變子進程的頁表中這個變量對應的物理地址而虛擬地址不改變,這也就解釋了為什么一個地址會有兩個值的問題。如果沒有虛擬地址空間就沒有頁表也就不能實現獨立性。

二、保護數據安全

頁表是由操作系統去維護的如果想要去訪問一個不合法的地址或者是數據的話當查詢頁表的時候操作系統就可以去拒絕進而對數據形成了保護。

三、管理模塊和內存模塊的解耦合

task_struct,mm_struct等這是屬于管理模塊,物理內存等都是屬于內存模塊,以為有虛擬地址空間和頁表才會實現無論數據在物理內存是如何存儲的在虛擬內存空間都是有序的,這樣兩個模塊就可以解耦合。阻塞掛起也可以很好的展示管理模塊和內存模塊解耦合的好處,當進程是掛起狀態的時候,操作系統會把進程的代碼和數據換出到磁盤中,然后把頁表的物理地址刪除當進程調用數據和代碼的時候操作系統再換回到內存中,這也很好展示了管理和內存模塊是解耦合的。

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

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

相關文章

【iOS】消息傳遞和消息轉發

文章目錄前言一、消息傳遞&#xff1a;objc_msgSend 的“查字典遞歸找家長”流程1. 第一步&#xff1a;查“最近調用記錄”&#xff08;方法緩存&#xff09;—— 最快即快速查找&#xff01;2. 第二步&#xff1a;翻“自己的字典”&#xff08;類方法列表查找&#xff09;——…

MySQL查詢優化與事務實戰指南

本節用到的員工信息管理表結構放到資源中&#xff0c;需要的同學自取。本節內容以此表為示例&#xff1a; 面試題&#xff1a;innodb與myisam的區別。 外鍵&#xff0c;事務 特性InnoDBMyISAM事務支持支持不支持外鍵支持不支持鎖粒度行級鎖表級鎖索引結構聚簇索引非聚簇索引崩…

Windows 10/11 磁盤清理操作指南:徹底解決系統盤空間不足問題

&#x1f9d1; 博主簡介&#xff1a;CSDN博客專家、CSDN平臺優質創作者&#xff0c;高級開發工程師&#xff0c;數學專業&#xff0c;10年以上C/C, C#,Java等多種編程語言開發經驗&#xff0c;擁有高級工程師證書&#xff1b;擅長C/C、C#等開發語言&#xff0c;熟悉Java常用開發…

b-up:Enzo_Mi:深度學習基礎知識

1.最近鄰差值&#xff08;Neareast Neighbor Interpolation&#xff09; 插值算法 &#xff5c; 最近鄰插值法_嗶哩嗶哩_bilibili 上圖中最后一行&#xff0c;第一個圖像&#xff0c;因為目標像素&#xff08;放大后&#xff0c;位于第1行第0列的像素&#xff09;距離它最近的…

微信小程序商品結算功能

整體結算流程概述微信小程序的商品結算涉及前端交互、API調用和數據管理。典型流程包括&#xff1a;用戶交互&#xff1a;用戶選擇商品、填寫地址和時間。數據獲取&#xff1a;從小程序緩存或后端服務器獲取訂單信息。邏輯處理&#xff1a;驗證參數、應用紅包折扣。提交訂單&am…

2025年7月份最新一區算法——向光生長算法

注&#xff1a;該算法已按照智能優化算法APP標準格式進行整改&#xff0c;可直接集成到APP中&#xff0c;方便大家與自己的算法進行對比。&#xff08;近期智能優化算法APP將會迎來超級大更新&#xff01;請時刻保持關注哦&#xff01;&#xff09;向光生長算法&#xff08;Pho…

腳手架新建Vue2/Vue3項目時,項目文件內容的區別

一. package.json vue版本號不同vue2中會多一個依賴&#xff1a;vue-template-compiler&#xff0c;作用是預編譯Vue2模板為渲染函數&#xff0c;減少運行時開銷。vue-template-compiler與vue版本要保持一致&#xff0c;否則會報錯。eslintConfig中的extends不同 eslintConfig…

微信小程序入門實例_____從零開始 開發一個每天記賬的微信小程序

在前面的微信小程序實例中我們開發了體重記錄等實用小程序&#xff0c;今天來嘗試一個和生活消費緊密相關的 ——“每日記賬小程序”。它能幫你隨時記錄收支情況&#xff0c;讓每一筆花費都清晰可查。下面就跟著步驟&#xff0c;一步步構建這個小程序。?體驗一個開發者的快樂。…

2026python實戰——如何利用海外代理ip爬取海外數據

家人們&#xff01;隨著跨境電商的發展&#xff0c;是不是越來越多的小伙伴們也開始搞海外的數據分析了&#xff1f;不過雖然我們已經整天爬蟲、數據采集打交道了&#xff0c;但一到海外數據&#xff0c;還是有不少人掉進坑里。你們是不是也遇到過以下情況&#xff1a;花了一堆…

Spring Boot啟動原理:從main方法到內嵌Tomcat的全過程

Spring Boot的啟動過程是一個精心設計的自動化流程&#xff0c;下面我將詳細闡述從main方法開始到內嵌Tomcat啟動的全過程。 1. 入口&#xff1a;main方法 一切始于一個簡單的main方法&#xff1a; SpringBootApplication public class MyApplication {public static void m…

小白學Python,網絡爬蟲篇(1)——requests庫

目錄 一、網絡爬蟲的介紹 1.網絡爬蟲庫 2.robots.txt 規則 二、requests 庫和網頁源代碼 1.requests 庫的安裝 2.網頁源代碼 三、獲取網頁資源 1.get () 函數 &#xff08;1&#xff09;get() 搜索信息 &#xff08;2&#xff09;get() 添加信息 2.返回 Response 對象…

平板可以用來辦公嗎?從文檔處理到創意創作的全面測評

在快節奏的現代職場&#xff0c;一個核心疑問始終縈繞在追求效率的職場人心中&#xff1a;平板電腦&#xff0c;這個輕薄便攜的設備&#xff0c;真的能替代筆記本電腦&#xff0c;成為值得信賴的辦公伙伴嗎&#xff1f; 答案并非簡單的“是”或“否”&#xff0c;而是一個充滿潛…

docker gitlab 備份 恢復 版本升級(16.1.1到18.2.0)

docker 啟動 # 在線 docker pull gitlab/gitlab-ce:latest # 離線 docker save -o gitlab-ce-latest.tar gitlab/gitlab-ce:latest docker load -i gitlab-ce-latest.tardocker run --detach \--publish 8021:80 --publish 8023:22 \ --name gitlab_test \--restart always \-…

web3 區塊鏈技術與用

#53 敲點算法題 瑞吉外賣day4 調整心態 睡眠 及精神 web3 以下是應北京大學肖臻老師《區塊鏈技術與用》公開課的完整教學大綱&#xff0c;綜合課程內容、技術模塊及前沿擴展&#xff0c;分為核心章節與專題拓展兩部分&#xff0c;引用自公開課資料及學員筆記。 &#x1f4…

Redis1:高并發與微服務中的鍵值存儲利器

redis中存儲的數據格式為鍵值對&#xff08;Key,Value&#xff09;在高并發的項目和微服務的項目會頻繁的用到redisNoSQL型數據庫1.初始Redis1.1認識NoSQLSQL&#xff1a;structure query language關系型數據庫結構化&#xff1a;有固定格式要求&#xff08;表關系&#xff0c;…

/字符串/

字符串 個人模板 5. 最長回文子串 93. 復原 IP 地址 43. 字符串相乘 227. 基本計算器 II

我的開發日志:隨機數小程序

文章目錄前言UI設計代碼前言 為什么我要設計這個程序呢&#xff1f;因為我要用&#xff0c;懶得在網上下載了&#xff0c;于是干脆寫了一個。 UI設計 UI是我凹出來的&#xff0c;你們要使用&#xff0c;直接新建一個UI.ui文件&#xff0c;然后把下面的東西輸進去就可以了。 …

《Oracle SQL:使用 RTRIM 和 TO_CHAR 函數格式化數字并移除多余小數點》

select RTRIM(to_char(1222.11123344,fm9999990.9999),.) from dual 這條 SQL 語句主要用于對數字進行格式化處理&#xff0c;并移除格式化結果右側多余的小數點。下面將詳細拆解該語句的執行過程和各部分作用。語句詳細拆解1. to_char(1222.11123344,fm9999990.9999)函數功能&…

「Java案例」方法重裝求不同類型數的立方

利用方法重裝實現不同類型數值的立方計算 立方計算方法的重載實現 編寫一個程序,要求編寫重載方法xxx cube(xxx value)實現對不同類型數值計算立方。 # 源文件保存為“CubeCalculator.java” public class CubeCalculator {public static void main(String[] args) {// 測試…

API 接口開發與接入實踐:自動化采集淘寶商品數據

在電商數據分析、價格監控等場景中&#xff0c;自動化采集淘寶商品數據具有重要價值。本文將詳細介紹如何通過 API 接口開發實現淘寶商品數據的自動化采集&#xff0c;包含完整的技術方案和代碼實現。 一、淘寶 API 接入基礎 1. 接入流程概述 注冊淘寶賬號獲取 ApiKey 和 Ap…