首页 > 系统相关 >虚拟内存到底是什么?为什么我们在C语言中看到的地址是假的?

虚拟内存到底是什么?为什么我们在C语言中看到的地址是假的?

时间:2022-10-05 18:56:55浏览次数:60  
标签:程序 虚拟地址 C语言 地址 内存 使用 内存地址 虚拟内存

在C语言中,指针变量的值就是一个内存地址,&运算符的作用也是取变量的内存地址,请看下面的代码:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int a = 1, b = 255;
  4. int main(){
  5. int *pa = &a;
  6. printf("pa = %#X, &b = %#X\n", pa, &b);
  7. system("pause");
  8. return 0;
  9. }
在 C-Free 5.0 下运行,结果为:
pa = 0X402000, &b = 0X402004

代码中的 a、b 是全局变量,它们的内存地址在链接时就已经决定了,以后再也不能改变,该程序无论在何时运行,结果都是一样的。

那么问题来了,如果物理内存中的这两个地址被其他程序占用了怎么办,我们的程序岂不是无法运行了?

幸运的是,这些内存地址都是假的,不是真实的物理内存地址,而是虚拟地址。虚拟地址通过CPU的转换才能对应到物理地址,而且每次程序运行时,操作系统都会重新安排虚拟地址和物理地址的对应关系,哪一段物理内存空闲就使用哪一段。如下图所示:

虚拟地址

虚拟地址的整个想法是这样的:把程序给出的地址看做是一种虚拟地址(Virtual Address),然后通过某些映射的方法,将这个虚拟地址转换成实际的物理地址。这样,只要我们能够妥善地控制这个虚拟地址到物理地址的映射过程,就可以保证程序每次运行时都可以使用相同的地址。

例如,上面代码中变量 a 的地址是 0X402000,第一次运行时它对应的物理内存地址可能是 0X12ED90AA,第二次运行时可能又对应 0XED90,而我们的程序不需要关心这些,这些繁杂的内存管理工作交给操作系统处理即可。

让我们回到程序的运行本质上来。用户程序在运行时不希望介入到这些复杂的内存管理过程中,作为普通的程序,它需要的是一个简单的执行环境,有自己的内存,有自己的CPU,好像整个程序占有整个计算机而不用关心其他的程序。

除了在编程时可以使用固定的内存地址,给程序员带来方便外,使用虚拟地址还能够使不同程序的地址空间相互隔离,提高内存使用效率。

使不同程序的地址空间相互隔离

如果所有程序都直接使用物理内存,那么程序所使用的地址空间不是相互隔离的。恶意程序可以很容易改写其他程序的内存数据,以达到破坏的目的;有些非恶意、但是有 Bug 的程序也可能会不小心修改其他程序的数据,导致其他程序崩溃。

这对于需要安全稳定的计算机环境的用户来说是不能容忍的,用户希望他在使用计算机的时候,其中一个任务失败了,至少不会影响其他任务。

使用了虚拟地址后,程序A和程序B虽然都可以访问同一个地址,但它们对应的物理地址是不同的,无论如何操作,都不会修改对方的内存。

提高内存使用效率

使用虚拟地址后,操作系统会更多地介入到内存管理工作中,这使得控制内存权限成为可能。例如,我们希望保存数据的内存没有执行权限,保存代码的内存没有修改权限,操作系统占用的内存普通程序没有读取权限等。

另外,当物理内存不足时,操作系统能够更加灵活地控制换入换出的粒度,磁盘 I/O 是非常耗时的工作,这能够从很大程度上提高程序性能。

中间层思想

在计算机中,为了让操作更加直观、易于理解、增强用户体验,开发者经常会使用一件法宝——增加中间层,即使用一种间接的方式来屏蔽复杂的底层细节,只给用户提供简单的接口。虚拟地址是使用中间层的一个典型例子。

实际上,计算机的整个发展过程就是不断引入新的中间层:
  • 计算机的早期,程序都是直接运行在硬件之上,自己负责硬件的管理工作;程序员也使用二进制进行编程,需要处理各种边界条件和安全问题。
  • 后来人们不能忍受了,于是开发出了操作系统,让它来管理各种硬件,同时发明了汇编语言,减轻程序员的负担。
  • 随着软件规模的不断增大,使用汇编语言编程开始变得捉襟见肘,不仅学习成本高,开发效率也很低,于是C语言诞生了。C语言编译器先将C代码翻译为汇编代码,再由汇编器将汇编代码翻译成机器指令。
  • 随着计算机的发展,硬件越来越强大,软件越来越复杂,人们又不满足于使用C语言了,于是 C++、Java、C#、PHP 等现代化的编程语言诞生了。

标签:程序,虚拟地址,C语言,地址,内存,使用,内存地址,虚拟内存
From: https://www.cnblogs.com/xkdn/p/16756118.html

相关文章

  • C语言课程设计
    沈阳航空航天大学  课程设计报告  课程设计名称:C语言课程设计课程设计题目:通用排序程序的设计与实现    院(系):计算机学院专   业:计算机科学......
  • C语言 初识C语言03
    变量生活中有些值是不变的,有些值是可变的。不变的值,C语言中用常量的概念来表示,变的值C语言用变量来表示。1、定义变量的方法intage=100;floatweight=45.5f;charch='w......
  • 树的存储结构(双亲表示法,孩子表示法,孩子兄弟表示法)——C语言描述
    树的存储结构(双亲表示法,孩子表示法,孩子兄弟表示法)——C语言描述目录树的存储结构(双亲表示法,孩子表示法,孩子兄弟表示法)——C语言描述0测试用例框架1树的基本概念2树的存......
  • C语言-float和double的区别。
    类型     符号位阶码 尾数 长度float      1     8    23   32double    1    11    52   64double......
  • C语言-运算符 sizof与strlen的区别
    1、sizeof是运算符,strlen是C语言标准库函数。2、 strlen 测量的是字符串的实际长度,以’\0’结束,返回结果不包括’\0’。3、而sizeof测量的是字符的分配大小,它的参数可......
  • 初学C语言笔记221005
    realloc调整动态内存开辟空间的大小​int*p1=(int*)malloc(10*sizeof(int));​if(p1==NULL){printf("%s",strerror(errno));}else{*p1=0x12345678;*......
  • c语言第七课
    字符串与字符数组字符数组定义chararray[1000];字符数组初始化chararray[100]={'a','b','c','d'};chararray[100]="abcd";chararray[100]={0}; //但凡为......
  • C语言学习记录3
    #每日美图分享##include<stdio.h>intmain(){inti=1;while(i<=10){if(i==5)continue;printf("%d\n",i);i++;}return0;}该代码的运行结果为:1234而......
  • C语言每日一题——第八天
    第八天小明学习到了数组,同时,在最近的开发中,他发现很多递归运算存在重复计算相同数值的问题。他决定利用数组缓存运算的结果。有一个数组\(a_{n}\),已知\(a_n=a_{n-2}-......
  • 【C语言】循环语句
    ......