【Linux内核大揭秘】程序地址空间

在这里插入图片描述

文章目录

  • 什么是程序地址空间
    • 地址空间的组成
    • 虚拟内存技术
  • 如何理解程序地址空间
    • 页表
    • 页表的细节
    • 关于堆区
  • 在Linux中如何查看各个分段的信息
  • 总结

什么是程序地址空间

程序地址空间是一个程序在执行期间可以访问的内存范围。它由操作系统为每个进程分配,以确保进程之间不会相互干扰。地址空间包含了程序所需的所有内存区域,包括代码、已初始化和未初始化的数据、堆(heap)、栈(stack)等。

地址空间的组成

地址空间分为逻辑地址物理地址两种:

  • 逻辑地址:是程序在代码中使用的地址,不直接对应物理内存。每个进程都有独立的逻辑地址空间。
  • 物理地址:是真正存储在内存中的位置。

虚拟内存技术

通过虚拟内存技术,操作系统将逻辑地址映射到物理地址。这种技术带来了以下优势:

  1. 内存隔离:每个进程可以使用相同的逻辑地址空间,而操作系统会隔离各自的实际内存,确保进程之间不会互相影响。
  2. 安全性和稳定性:这种隔离机制使得进程无法直接访问其他进程的内存,提高了系统的安全性和稳定性。

总结来说,程序地址空间通过虚拟内存和地址映射技术实现了进程的内存隔离,保障了多任务操作系统的安全和可靠性。

如何理解程序地址空间

通过一个现象来了解什么是虚拟内存技术。
下面写一个简单的程序:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int gval=100;
int main()
{printf("我是一个进程:pid:%d,ppid:%d\n",getpid(),getppid());pid_t id = fork();if(id==0){//childwhile(1){printf("我是子进程,pid:%d,ppid:%d,gval:%d,&gval:%p\n",getpid(),getppid(),gval,&gval);gval++;sleep(1);}}else{//parentwhile(1){printf("我是父进程,pid:%d,ppid:%d,gval:%d,&gval:%p\n",getpid(),getppid(),gval,&gval);sleep(1);}}return 0;
}

这个程序很简单,通过父进程创建了一个子进程,然后用一个全局变量来证明虽然父子进程共用一套代码,但是数据是分离开的。
我们分别打印全局变量的数据和全局变量的地址,然后子进程对应的全局变量需要做++操作。
我们来看看运行结果:
在这里插入图片描述
可以看见两个全局变量的地址是相同的,但是还是做到了数据独有呢?这是怎么做到的,通过这个现象,我们可以看出gval的地址肯定不是物理内存的地址,如果是物理内存的地址,如果地址相同,那么值也应该相同,所以这里面肯定是用什么结构把真实的物理内存给保护起来了,首先我们来看看我们以前学过的内存的结构。
在这里插入图片描述

这是我们以前了解到的内存的划分区域,从上面现象可以推出这不是程序地址空间,而是进程地址空间,操作系统为每个进程绘制了一个虚拟地址内存,让每个进程以为自己独占整个内存,进程彼此之间是不知道的,从而达到了一定程度上的隔离。
实际上所谓的进程虚拟地址空间本质上是一个内核数据结构(内似于PCB)。
这个内核数据结构叫做mm_struct,在PCB中有一个指针指向虚拟地址空间,PCB控制着这个虚拟地址空间,然后mm_struct通过映射,映射到真实的物理内存上。
我们画一个简图来理解这个概念:
在这里插入图片描述
如何证明确实在task_struct中有这样一个结构体指针呢,我们来看看Linux内核的原码:
在这里插入图片描述

可以看见task_struct内部确实有一个这样的指针,我们来看看mm_struct内部是什么样的:
在这里插入图片描述
可以看见在mm_struct中有一些start和end的成员变量,这些就代表各个区域的起始位置和末尾位置,地址也是一个数,所以我们可以用一个unsigned long类型来表示每个区域的起始位置和末尾位置。
在这里插入图片描述
虽然我们知道我们取到的地址不是物理内存地址,而是虚拟内存地址,中间是通过一层映射关系来将虚拟内存地址转化为物理内存地址的,那中间到底是怎么做到的,其实在这中间起着关键作用的,有一个内核数据结构叫做页表。

页表

在这里插入图片描述

什么是页表:
页表是操作系统内核用来管理虚拟地址和物理地址之间映射的一个数据结构。它的核心作用是支持虚拟内存,使得每个进程可以在自己的独立虚拟地址空间中运行,增强了内存隔离和安全性。
简单了解完页表后,我们来解释一下我们刚刚的现象,为什么父进程的gval不变,子进程的gval在改变,两个gval都指向同一块空间。
在这里插入图片描述
首先父进程创建子进程会以自己为模版创建一个PCB,内核会为子进程创建一个新的mm_struct,mm_struct的大部分字段和和父进程共享,页表也会被创建,所以这里物理地址指向的是同一块空间。
但是当我们修改gval的时候,物理内存会发生写实拷贝,父子进程不再共享gval。
在这里插入图片描述
子进程的gval对应的虚拟地址对应的页表的映射会改变,改变为写实拷贝过后的地址,这样当修改gval时,gval会修改,但是父进程的gval不会被修改,但是gval的地址都是相同的,是因为这是虚拟地址,子进程是以父进程为模版创建的。

页表的细节

关于页表,其实页表不存储物理地址和虚拟地址。
在这里插入图片描述
当中还存在权限的管理和标记位等等属性,这个权限管理指的是读写权限,就比如我们在C语言中遇到的下图:
在这里插入图片描述
这个都知道会崩溃,但是为什么会崩溃,其实是因为str对应的权限只有读,没有写的权限,所以会直接崩溃,这时系统层面上的错误,不是语法层面上的错误,所以语法是不会报错的。
有效位表示看目标数据是否存在于内存当中,如果该位为 0,意味着页面不在物理内存,访问该页面会触发缺页中断,操作系统会加载页面或进行错误处理。
页表其实还有很多属性,这里只陈述这两个属性。

关于堆区

我们new出来的空间是否是物理内存?—答案很显然不是的。
我们new或者malloc出来的空间也是虚拟内存,有一个问题就来了,结构体就那么大,但是堆区是动态的,那他是如何实现动态开辟的呢,刚刚我们提到了mm_struct有一段区域是存储begin和end的,我们只需要改变end和begin的数字,即可控制虚拟内存。
在这里插入图片描述

在Linux中如何查看各个分段的信息

readelf -S 文件名

在这里插入图片描述

总结

通过本篇文章,我们了解了 Linux 程序地址空间的基本结构和分布,包括代码段、数据段、堆、栈以及内核空间的划分。掌握程序地址空间的布局不仅能帮助我们理解进程的内存使用,还能为调试、性能优化和内存管理打下坚实基础。理解 mm_struct、页表以及写时复制等机制,也为深入探索操作系统内核的内存管理提供了关键的思路。希望这些内容能让你在实际开发和学习中更好地应用这些知识,为系统性能和安全性提供支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/2992.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

nginx代理出现的请求头中获取不到acc_token问题

1.问题 程序开发完成之后&#xff0c;发现页面登录之后&#xff0c;获取不到用户信息。发现时没有获取到token信息。本地程序开发完成&#xff0c;后端服务成功署到服务器。通过云服务器开放对应的端口&#xff0c;使用本地的前端服务&#xff0c;直接连接服务器后端服务&…

WordPress之generatepress主题安装

1.打开主题列表 2.如果没有自己需要主题点击安装新主题 点击安装并启用 3.不喜欢的 主题可以点击主题进去删除 4.主题自定义编辑 打开自定义&#xff0c;可以修改布局&#xff0c;颜色&#xff0c;排版等等

MySQL之JDBC入门详解

01-JDBC入门 一、JDBC概念 jdbc : java database connection , java数据库连接 jdbc是sun公司定义的java程序访问数据库的规范。 二、JDBC操作需要6步 三、入门程序 1、使用eclipse打开一个新的工作空间 2、切换到java视图界面 3、创建java工程&#xff1a;01-jdbc-helloworl…

BackTrader-Commission 06

Backtrader 策略实例&#xff0c;该部分内容通过使用backtrader对常用的策略实例的编写&#xff0c;提高和熟悉backtrader的实际场景的使用。 [Backtrader]实例:均线策略 [Backtrader] 实例:MACD策略 [Backtrader] 实例:KDJ 策略 [Backtrader] 实例:RSI 与 EMA 结合 [Backtrade…

WordPress伪静态设置

为什么要设置WordPress伪静态&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;中&#xff0c;静态URL通常被认为更易于搜索引擎爬虫抓取和索引&#xff0c;有助于提高网站的搜索引擎排名。 WordPress伪静态设置方法主要依赖于服务器环境&#xff0c;以下是针对不同服务器…

sublime python出现中文乱码怎么办

一、乱码现象 利用sublime自带编译快捷方式ctrlB会出现中文乱码的情况。 print("没有循环数据!") print("完成循环!") 二、寻找原因 1、由于之前我已经安装了插件ConvertToUTF8&#xff0c;排除文本编码错误问题。 2、相同的代码在插件sublimerepl搭建的…

【ARM Linux 系统稳定性分析入门及渐进 1.2 -- Crash 工具依赖内容】

请阅读:【Linux 维测及Crash使用专栏】 文章目录 Prerequisites1. 内核对象文件2. 内存镜像3. 平台处理器类型4. Linux 内核版本 Prerequisites crash 工具需要依赖下面的内容&#xff1a; 1. 内核对象文件 vmlinux 文件&#xff1a;需要一个 vmlinux 内核对象文件&#xff…

电路设计过程就是波形整形过程

这种说法有一定的道理。在电路设计中&#xff0c;常常需要对输入的电信号波形进行处理和调整&#xff0c;以满足后续电路或系统的要求&#xff0c;这在某种程度上可以理解为波形整形的过程。 例如&#xff0c;在数字电路中&#xff0c;输入的信号可能存在噪声、干扰或者不符合…

计算机视觉-显著性检测实验报告

实验四 显著性检测实验 一、实验目的 掌握多种显著性检测算法的基本原理。学会使用计算机程序实现不同的显著性检测方法。通过对比不同的显著性检测算法&#xff0c;理解各算法的优缺点。分析显著性检测在实际图像处理应用中的效果和局限性。 二、实验内容和要求 1&#x…

05-Dubbo的应用及注册和SPI机制

05-Dubbo的应用及注册和SPI机制 Dubbo 的服务注册中应用级注册优化 Dubbo 的注册中心 Dubbo 支持很多种注册中心&#xff0c;支持的主流注册中心包括&#xff1a;ZooKeeper、Nacos、Redis Dubbo 需要引入注册中心依赖&#xff0c;并且配置注册中心地址&#xff0c;这里以 ZooKe…

【 AI 大模型:重塑软件开发的新势力】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

南宁周边乡村游微信小程序ssm+论文源码调试讲解

第二章 开发工具及关键技术介绍 2.1微信开发者工具 微信开发者工具现在已经被小程序开发团队开发运行&#xff0c;目前微信开发者工具任然在不断的完善中&#xff0c;在开发小程序时经常要不断的更新。可以使用微信扫码登陆开发者工具&#xff0c;开发者工具将使用这个微信帐号…

ssm校园二手交易管理系统+vue

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码看文章最下面 需要定制看文章最下面 目 录 1 绪论 1 1.1 选题背景 1 1.2 选题意义 1 1.3 研究内容 2 2 系统开发技术 3 2.1 MySQL数…

DB-GPT系列(二):DB-GPT部署(镜像一键部署、源码部署)

一、简介 DB-GPT 是一个开源项目&#xff0c;其将大语言模型 LLM 与数据库紧密结合。该项目主要致力于探索如何让预训练的大规模语言模型&#xff08;例如 GPT&#xff09;能够直接与数据库进行交互&#xff0c;从而生成更为准确且信息丰富的回答。 DB-GPT部署后能否直接使用…

掌握 Jest 配置文件:优化单元测试的灵活性与可维护性

引言 在现代软件开发中&#xff0c;单元测试是确保代码质量和稳定性的关键步骤。Jest 是一个广泛使用的 JavaScript 测试框架&#xff0c;提供了丰富的配置选项来优化测试过程。通过配置文件&#xff0c;开发者可以更灵活地控制测试环境&#xff0c;确保测试的可靠性和可维护性…

网络:IP分片和组装

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言16位标识&#xff0c;3位标志&#xff0c;13位片偏移分片组装总结 前言 对于IP分片和组装的总结 当一个IP数据报的大小超过网络的MTU(最…

Node.js:Express 中间件 CORS 跨域资源共享

Node.js&#xff1a;Express 中间件 & CORS 中间件全局中间件局部中间件分类错误级中间件内置中间件 CORS原理预检请求 中间件 中间件是不直接接收请求&#xff0c;也不直接发送响应&#xff0c;而是在这之间处理一个中间过程的组件。 当一个请求到来&#xff0c;会经过多…

【VScode】中文版ChatGPT编程工具-CodeMoss!教程+示例+快捷键

文章目录 1. 多模型选择2. 编辑快捷键3. 历史记录收藏 CodeMoss使用教程1. 安装CodeMoss插件2. 配置AI模型3. 使用快捷键4. 进行代码优化与解释5. 收藏历史记录 总结与展望 在当今快速发展的编程世界中&#xff0c;开发者们面临着越来越多的挑战。如何提高编程效率&#xff0c;…

LabVIEW适合开发的软件

LabVIEW作为一种图形化编程环境&#xff0c;主要用于测试、测量和控制系统的开发。以下是LabVIEW在不同应用场景中的适用性和优势。 一、测试与测量系统 LabVIEW在测试与测量系统中的应用广泛&#xff0c;是工程测试领域的主流工具之一。利用其强大的数据采集与处理功能&…

命令模式(Command)

1 意图 将一个请求封装为一个对象&#xff0c;从而使得可以用不同的请求对客户进行参数化;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 2 结构 Command 声明执行操作的接口。ConcreteCommand 将一个接收者对象绑定于一个动作;调用接收者相应的操作&#xff0c…