C语言中的虚拟地址

虚拟地址

虚拟地址空间

  • 对于操作系统而言,每个进程所得到的虚拟地址都在一个独立的固定的范围内,不会超过这个范围,我们把这个范围称为虚拟地址空间。
  • 所谓的虚拟地址空间本质就是一个地址范围,表示程序的寻址能力。
  • 对于32位系统而言,虚拟地址空间从0x00000000~0xFFFFFFFF,也就是4G
    • 0 ~ 3G-1是归用户所使用,称为用户地址空间
    • 3G ~ 4G-1是归内核使用,称为内核地址空间
  • 对于64位系统而言,因为应用程序没有那么大的内存需求,所以不支持完全的64位虚拟地址
    • 0x0000 0000 0000 0000 ~ 0x0000 FFFF FFFF FFFF是用户地址空间
    • 0xFFFF 0000 0000 0000 ~ 0xFFFF FFFF FFFF FFFF是内核地址空间
    • 内核地址空间和用户地址空间直接是不规范地址空间,不允许使用,强制使用会出现段错误
    • 用户地址空间的代码不能直接访问内核空间的代码和数据,但可以通过系统调用进入内核态,间接与系统内核交互

以下是一个32位系统存储数据的示例图

在这里插入图片描述

从上图中可以看到每个进程都有自己独立的虚拟地址池,它们之间相互隔离,不会相互干扰或冲突,当给内核操作的虚拟地址没有在映射关系表中找到对应关系时,就会出现段错误

虚拟地址空间布局

  • 程序中不同性质的数据,加载到内存中,其虚拟地址会被映射到虚拟地址空间中不同区域

在这里插入图片描述

代码如下:

// 虚拟地址空间布局
#include <stdio.h>
#include <stdlib.h>const int const_global = 1;  // 常全局变量
int init_global = 2;  // 初始化全局变量
int uninit_global;  // 未初始化全局变量int main(int argc, char *argv[], char *envp[])
{static const int const_static = 3;  // 常静态变量static int init_static = 4;  // 初始化静态变量static int uninit_static; // 未初始化静态变量const int const_local = 5;  // 常局部变量int local;  // 局部变量char *string = "hello";  // 字面值常量int *heap = malloc(sizeof(int)); // 堆变量printf("----------参数和环境----------\n");printf("         命令行参数: %p\n", argv);printf("           环境变量: %p\n", envp);printf("------------栈区-------------\n");printf("         常局部变量: %p\n", &const_local);printf("           局部变量: %p\n", &local);printf("------------堆区-------------\n");printf("             堆变量: %p\n", heap);printf("------------BSS区-------------\n");printf("    未初始化全局变量: %p\n", &uninit_global);printf("    未初始化静态变量: %p\n", &uninit_static);printf("------------数据区-------------\n");printf("      初始化全局变量: %p\n", &init_global);printf("      初始化静态变量: %p\n", &init_static);printf("------------代码区-------------\n");printf("          常全局变量: %p\n", &const_global);printf("          常静态变量: %p\n", &const_static);printf("          字面值常量: %p\n", string);printf("               函数: %p\n", main);printf("-------------------------------\n");return 0;
}

内存映射的建立与解除

  • 没有与物理地址建立映射关系的虚拟地址,无法直接使用,如果强行使用被报段错误,我们可以通过系统调用mmap函数手动建立虚拟地址和物理地址之间的映射关系。
  • 补充:基本上所有的头文件都是放在这个路径下的:/usr/include
  • 下面那个函数需要引入mman.h这个头文件:#include <sys/mman.h>
  • mmap函数
    • void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
      • 功能:建立虚拟内存到物理内存或磁盘文件的映射
      • 参数
        • start:映射区虚拟内存的起始地址,NULL系统自动选定后返回。
        • length:映射区字节数,自动按页圆整,4k为一页。
        • prot:映射区操作权限,可取以下值,多选使用|隔开
          • PROT_READ:映射区可读
          • PROT_WRITE:映射区可写
          • PROT_EXEC:映射区可执行
          • PROT_NONE:映射区不可访问
        • flags:映射标志,可取以下值,多选使用|隔开
          • MAP_ANONYMOUS:匿名映射,将虚拟内存映射到物理内存中而非文件,使用这个就可以忽略df和offset参数,将这两个参数设为0即可
          • MAP_PRIVATE:对映射区的写操作只反映到缓冲区并不会真正写入文件,与MAP_SHARED二选一,不能同时存在
          • MAP_SHARED:对映射区的写操作直接反映到文件中
          • MAP_DENYWRITE:拒绝其他对文件的写操作
          • MAP_FIXED:若在start上无法创建映射,则失败(无此标志系统会自动调整)
        • fd:文件描述符,flags使用MAP_ANONYMOUS时,这里填0即可
        • offset:文件偏移量,自动按页(4K)对齐,flags使用MAP_ANONYMOUS时,这里填0即可
      • 返回值:成功返回映射区虚拟地址的起始地址,失败返回MAP_FAILED(-1)
  • munmap函数
    • int munmap(void *start, size_t length);
      • 功能:解除虚拟内存到物理内存或磁盘文件的映射
      • 参数:
        • start:映射区虚拟内存的起始地址
        • length:映射区字节数,自动按页圆整,4k为一页
      • 返回值:成功返回0,失败返回-1
      • munmap允许对映射区的一部分映射,但必须按页处理

使用示例:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>int main(void)
{// 1. 建立映射: 返回值是void*类型,这里使用的是char*,内部会自动强转的char *start = mmap(NULL, 8192, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);if(start == MAP_FAILED){perror("mmap");return -1;}// 2. 写入数据strcpy(start, "哈哈");printf("输出: %s\n", start);// 3. 解除一部分映射if(munmap(start, 4096) == -1){perror("munmap");return -1;}// strcpy(start, "呵呵");  // 这里测试使用了已经解除的虚拟地址,出现了 段错误 (核心已转储)// 4. 在剩下的那一部分中写入数据start += 4096;  // 首先先将start往上移strcpy(start, "嘿嘿");printf("输出: %s\n", start);// 5. 解除if(munmap(start, 4096) == -1){perror("munmap");return -1;}return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直播视频处理过程

视频其实就是快速播放一连串连续的图片。 每一张图片&#xff0c;我们称为一帧。只要每秒钟帧的数据足够多&#xff0c;也即播放得足够快。比如每秒 30 帧&#xff0c;以人的眼睛的敏感程度&#xff0c;是看不出这是一张张独立的图片的&#xff0c;这就是我们常说的帧率&#…

03-JavaScript-函数

函数就是将特定功能的代码封装起来&#xff0c;当需要实现特定功能时&#xff0c;直接调用函数实现即可。 一、函数定义和使用 1.1 定义函数 语句式命名函数 function sum(a,b) {return a b; }变量函数表达式 是一个匿名函数&#xff0c;它没有函数名 let sum function(…

如何用一行CSS实现10种现代布局

现代 CSS 布局使开发人员只需按几下键就可以编写十分有意义且强大的样式规则。上面的讨论和接下来的帖文研究了 10 种强大的 CSS 布局&#xff0c;它们实现了一些非凡的工作。 超级居中&#xff1a;place-items: center 对于第一个“单行”布局&#xff0c;让我们解决所有 CSS…

缓存读写淘汰算法W-TinyLFU算法

在W-TinyLFU中&#xff0c;每个缓存项都会被赋予一个权重。这个权重可以表示缓存项的大小、使用频率、是否是热数据等因素。每次需要淘汰缓存时&#xff0c;W-TinyLFU会选择小于一定阈值的权重的缓存项进行淘汰&#xff0c;以避免淘汰热数据。 另外&#xff0c;W-TinyLFU也会根…

分析数组,结构体在反汇编中存储

本文会在IDA中分析数组&#xff0c;结构体在内存中的存储 目录 IDA分析数组存储 IDA分析结构体存储 传递参数的方式 IDA分析数组存储 测试代码如下&#xff1a; /************************************************************************/ /*Author : 玄都大…

已解决 Kotlin Error: Null can not be a value of a non-null type String

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

Intel汇编在VS下开发的环境配置

1. 创建一个C/C的空项目 2. 创建汇编源码文件, 就是C文件改后缀为asm 3. 在生成依赖项一栏中选择自定义 4. 选择masm 5. 在源文件上右击选择属性 6. 这么设置一下 7. 为了让代码看的更舒服一些, 添加一些高亮插件 8. 安装AsmHighligher和AsmDude插件(非必须), 其中前者主要是高…

signal(SIGPIPE, SIG_IGN)

linux查看signal常见信号。 [rootplatform:]# kill -l1) HUP2) INT3) QUIT4) ILL5) TRAP6) ABRT7) BUS8) FPE9) KILL 10) USR1 11) SEGV 12) USR2 13) PIPE 14) ALRM 15) TERM 16) STKFLT 17) CHLD 18) CONT 19) STOP 20) TSTP 21) TTIN 22) TTOU 23) URG 24) XCPU 25) XFSZ 2…

【动态规划刷题 16】最长等差数列 (有难度) 等差数列划分 II - 子序列

1027. 最长等差数列 https://leetcode.cn/problems/longest-arithmetic-subsequence/ 给你一个整数数组 nums&#xff0c;返回 nums 中最长等差子序列的长度。 回想一下&#xff0c;nums 的子序列是一个列表 nums[i1], nums[i2], …, nums[ik] &#xff0c;且 0 < i1 <…

学Python的漫画漫步进阶 -- 第十一步.常用的内置模块

学Python的漫画漫步进阶 -- 第十一步.常用的内置模块 十一、常用的内置模块11.1 数学计算模块——math11.2 日期时间模块——datetime11.2.1 datetime类11.2.2 date类11.2.3 time类11.2.4 计算时间跨度类——timedelta11.2.5 将日期时间与字符串相互转换 11.3 正则表达式模块—…

音乐随行,公网畅享,群辉Audiostation给你带来听歌新体验!

文章目录 本教程解决的问题是&#xff1a;按照本教程方法操作后&#xff0c;达到的效果是本教程使用环境&#xff1a;1 群晖系统安装audiostation套件2 下载移动端app3 内网穿透&#xff0c;映射至公网 很多老铁想在上班路上听点喜欢的歌或者相声解解闷儿&#xff0c;于是打开手…

代码随想录算法训练营第23期day2 | 977.有序数组的平方 、209.长度最小的子数组、59.螺旋矩阵II

目录 一、&#xff08;leetcode 977&#xff09;有序数组的平方 1.暴力解法 2.双指针法 二、&#xff08;leetcode 209&#xff09;长度最小的子数组 1.暴力解法 ​编辑2.滑动窗口 三、&#xff08;leetcode 59&#xff09;螺旋矩阵II 一、&#xff08;leetcode 977&…

ChatGLM 配置CUDA使用GPU本地训练

Cuda的下载及安装 cuda版本 由于显卡的不同,需要先查看我们显卡及驱动最高支持的cuda。 进入cmd输入nvidia -smi 版本支持向下兼容,为了保证能够和其他开发库版本兼容,这里使用的CUDN版本为11.6. cuda下载 CUDA Toolkit| NVIDIA Developer官网找到对应CUDA版本。(我这里…

【Python基础】S01E02 列表

S01E02列表 列表是什么列表的操作修改、添加和删除元素列表排序列表倒序列表长度遍历整个列表 数值列表创建数值列表数值列表简单统计计算列表推导式 列表切片复制列表 列表是什么 在Python中&#xff0c;用方括号&#xff08;[ ]&#xff09;表示列表&#xff0c;用逗号分隔其…

基于Java的Base64编解码优化探讨

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

eclipse svn插件安装

1.进入eclipse的help->Eclipse Marketplace,如下图所示&#xff1a; 2.输入“svn”,再按回车&#xff0c;如下图&#xff1a; 3.这我选择的是 Subversive,点击后面的“install”按钮&#xff0c;如下图 Eclipse 下连接 SVN 库有两种插件 —— Subclipse 与 Subversive &…

java面向对象(八)

文章目录 一、abstract关键字的使用1.概念2. abstract修饰类:抽象类3.abstract修饰方法&#xff0c;抽象方法4.abstract使用上的注意点&#xff1a;5.抽象类的匿名子类 二、计算一段代码执行所花费的时间三、接口的使用1.接口的使用2.定义接口中的成员3.代码demo4.Java类可以实…

uniapp:APP开发,后台保活

前言&#xff1a; 在ios中&#xff0c;软件切换至后台、手机息屏&#xff0c;过了十来秒软件就会被系统挂起&#xff0c;APP内的任务就不能继续执行&#xff1b;在android中&#xff0c;默认情况下&#xff0c;软件在后台运行的时候&#xff0c;触发某些特定条件的情况下&…

高性能实践

1、认识性能 从用户体验来看&#xff0c;性能就是响应时间短&#xff1b; 从开发角度来看&#xff0c;性能主要是执行效率高。 性能主要表现形式如下&#xff1a; &#xff08;1&#xff09;响应时间&#xff0c;AVG、MAX、MIN、TP95、TP99 &#xff08;2&#xff09;吞吐…

物联网网关:连接设备与云端的桥梁

物联网网关作为连接设备与云端的桥梁&#xff0c;承担着采集数据、设备远程控制、协议转换、数据传输等重要任务。物联网网关是一种网络设备&#xff0c;它可以连接多个物联网设备&#xff0c;实现设备之间的数据传输和通信。物联网网关通常具有较高的网络带宽和处理能力&#…