每天3分钟操作系统修炼秘籍(8):虚拟内存分段

点我查看秘籍连载

进程的地址空间布局:分段

Linux的虚拟地址空间采用“分段+分页”结合的方式实现。先看分段,之后再介绍分页。

分段是将内存划分成各个段落(Segment),每个段落的长度可以不同,且虚拟地址空间中未使用的空间不会映射到物理内存中,所以操作系统不会为这段空间分配物理内存。这样的话,内核为刚创建的进程分配的物理内存可以很小,随着进程运行不断使用内存,内核再为进程按需分配物理内存。也就是说,尽管地址空间的范围和物理内存大小一样,但不会将全部空间映射到物理内存。

对于Linux进程的虚拟地址空间来说,它的内存布局如下图。

虚拟空间分了如下几个段:

  • 文本段(Text):也称为代码段。进程启动时会将程序的代码加载到物理内存中,文本段映射到这片物理内存。
  • 初始化数据:包含程序显式初始化的全局变量和静态变量,这些数据是在程序真正运行前就已经确定的数据,所以可以提前加载到内存保存好。
  • 未初始化数据(BSS):未初始化的全局变量和静态变量,这些变量的值是在程序真正运行起来并为其赋值后才能确定的,所以程序加载之初,只需要记录它的内存地址和所需大小。出于历史原因,这段空间也称为BSS段。
  • 栈(Stack):是一个可以动态增长和收缩的内存段落,由栈帧(Stack Frames)组成,进程每调用一次函数,都将为该函数分配一个栈帧,栈帧中保存了该函数的局部变量、参数值和返回值。注意,编译器会将函数参数放入寄存器来优化程序,只有寄存器放不下的参数才使用栈帧来保存。
  • 堆(Heap):程序运行时,变量的值以及动态请求分配的内存都在这个内存段落中。
  • 内核段(Kernel):这部分是操作系统内核运行时所占用内存在各进程虚拟地址空间中的映射。所有进程都有,且映射地址相同,因为都映射到内核使用的内存。这段内存只有内核能访问,用户进程无法访问到该段落。

从上面的描述大概也能推测出,除了堆内存外,其它段落空间都是自动填充分配的,用户无法控制这些内存的使用。而堆内存段是用户能使用的自由内存区,绝大多数程序的用户数据都丢在这里面,算是一个大杂烩空间。

例如,下图中是一段C代码和内存布局之间的对应关系。

提示:其它语言的内存布局
上面的布局C程序的内存布局,也是Linux下进程的内存布局。其它语言(比如CPython)编写的程序运行起来后,只要是在Linux下运行,其进程的布局也会如此。只不过这些语言的程序中,全局变量、局部变量等可能和C的布局不一样,这和各语言的底层设计有关。比如C编写的某动态语言,它不要求指定变量的数据类型,那么在加载到内存的时候自然不知道该变量类型所需的空间大小,当它转换成C后(尽管不会真的转换成C代码),这个变量只能丢进堆内存作为动态数据。

使用分段的好处就是“各段自扫门前雪”,虽然在地址空间中每个分段的地址都是连续的,但实际上,每个分段映射到物理内存地址时是独立的,段与段之间可以不连续。这是因为CPU为每个段都使用一对(即两个)特殊的寄存器:基址寄存器和界限寄存器

而界限寄存器中的值用来表示该段在物理内存中的大小,即已为该段分配了多少内存。当准备用虚拟地址加基址计算物理地址时,需要先根据界限寄存器中的值检查将要访问的物理内存地址是否超出了这个段的范围。如果超出了,则表示访问了不属于该段的内存,也即内存的越界访问,而用户进程是没有权限访问其它进程或未分配内存的地址的,这时会收到一个SIGSEGV(segmentation violation)信号并提示:Segmentation Fault,即段错误或段异常。收到这个信号后默认情况下会终止该进程,因为它访问了非法地址,但是可以设置该信号的信号处理程序,从而做出其它处理。

例如,下图中的进程访问了Kernel段或者unallocated memory部分的内存,都会报错。Kernel段除了内核进程,任何用户进程都无法访问,典型的地址是用户进程想要访问0x0地址时,而该地址属于Kernel,所以报错。而unallocated memory是还未分配的内存,界限寄存器会保护该段无法访问。

再例如,C数组的越界访问时也会出现该问题。下图直观地显示了在Windows中同样的内存越界错误。

也就是说,基址寄存器是用来转换地址的,界限寄存器是用来保护进程不越界访问内存的。CPU借助基址寄存器和界限寄存器管理并提供地址翻译和内存保护的功能,通常称为内存管理单元(Memory Management Unit,MMU)。

最后再说明一点,内存地址翻译的任务既可以由操作系统来做,也可以由硬件CPU来做。但如果完全由操作系统来完成,就需要频繁地陷入到内核态,这样效率会非常低。所以,这项任务交给CPU硬件来完成,操作系统只需在必要的时候介入,比如分配内存、回收内存等。

原文地址:https://www.cnblogs.com/f-ck-need-u/p/11675346.html

时间: 2024-10-13 08:05:31

每天3分钟操作系统修炼秘籍(8):虚拟内存分段的相关文章

每天3分钟操作系统修炼秘籍(7):虚拟内存简介

点我查看秘籍连载 资源隔离:虚拟内存 前面描述的所有操作系统基础知识都是进程和CPU资源相关的内容,另一个操作系统中和进程相关的比较重要的话题是内存资源. 操作系统主要目的是执行程序,而程序在执行时,程序自身以及程序所访问的数据.所产生的数据都在内存里(至少所有数据的流向都会经过内存).此外,现代操作系统可以同时运行多个进程,而每个进程都有属于自己的一部分内存. 操作系统必须负责管理这些同时运行的这些进程的内存,并且还要保证进程A不会访问到进程B的内存,从而实现进程的隔离. 操作系统使用了一个称

每天3分钟操作系统修炼秘籍(12):OOM和swap分区

点我查看秘籍连载 OOM和swap分区 进程的虚拟内存空间是映射到整个物理内存空间的,所以在进程自身看来它拥有了整个物理内存,它也能使用整个物理内存,只需在使用的时候请求操作系统帮忙分配更多空间即可. 但是,操作系统上并非只运行了一个进程,如果一个进程无休止的申请物理内存空间,最终会导致物理内存耗尽或即将耗尽,使得操作系统无法创建新进程,因为创建新进程需要为它分配虚拟内存. 所以,操作系统必须得监视物理内存的使用情况,在出现物理内存耗尽或即将耗尽的时候,如果进程继续请求分配内存,将报错out-o

每天3分钟操作系统修炼秘籍(2):并行的假象和分时系统

点我查看秘籍连载 假象:"并行"运行多个进程 现代操作系统都支持多任务同时执行.在这里,操作系统对我们用户"营造了一种假象",让CPU看上去是用不完的,能够不断地添加新的程序使它们同时运行. 但每核CPU在某一时刻都只能执行一个进程.使用操作系统的人是不会去关注CPU是单核还是多核的,每个人都希望操作系统能同时运行多个程序,比如可以同时看网页.发邮件.聊QQ.听音乐等. 所以操作系统提供的多程序同时运行是"伪并行".要想实现真正的并行运行多个进程

转:攻城狮修炼秘籍

漫校园生活,孜孜不倦的你,今天书多读一点! 海康威视为你的假期精心准备了精神的饕餮大餐! 把自己投入知识的海洋吧!为即将成为一名高冷俊俏的程序猿和媛而吹响最后的号角: 各类秘籍自助区 一.测试攻城狮 <软件测试> <测试之道> 二.硬件攻城狮 基础理论:工程数学.积分变换.信号与系统.数字信号处理.自动控制原理.英语 专业课程:数电.模电.嵌入式系统.热设计.DDR3.flash.开关电源 (若有实践经验,可只看基础理论) 三.应用软件开发攻城狮 必读: <UNIX环境高级编

操作系统2015(四川大学软件学院)

1.操作系统是计算机系统的一种系统软件,它统一管理计算机系统的资源和控制程序的执行. 2.OS几大特征(1)并发(Concurrence),共享(Sharing),虚拟(Virtual),异步性(Asynchronism). (2) 其中最基本特征是并发和共享. 3.设计现代OS的目标是方便性,有效性,可扩充性和开放性. 4.批处理操作系统?用户准备好要执行的程序.数据和控制作业执行的说明书,由操作员输入到计算机系统中等待处理.操作系统选择作业并按作业说明书的要求自动控制作业的执行.采用这种批量

嵌入式操作系统内存管理有哪几种,各有何特性

嵌入式系统所用到的内存管理机制主要有以下两种: 1.虚拟内存管理机制: 有一些嵌入式处理器提供了MMU,在MMU具备内存地址映射和寻址功能,它使操作系统的内存管理更加方便.如果存在MMU ,操作系统会使用它完成从虚拟地址到物理地址的转换, 所有的应用程序只需要使用虚拟地址寻址数据. 这种使用虚拟地址寻址整个系统的主存和辅存的方式在现代操作系统中被称为虚拟内存.MMU 便是实现虚拟内存的必要条件.虚拟内存的管理方法使系统既可以运行体积比物理内存还要大的应用程序,也可以实现“按需调页”策略,既满足了

Linux 虚拟内存

什么是虚拟内存? 先直接摘抄一段 wikipedia 上的介绍. 虚拟内存是计算机系统内存管理的一种技术.它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上,它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换. 对于 C 语言里面的变量,我们可以使用 & 运算符来获得其地址, 既然是虚拟地址,就是指这个地址是虚拟的. 虚拟地址机制不是必须的,在简单的单片机中,编写的代码编译时都需要指定物理 RAM 空间分布,不会有虚拟地址的概念,

c++后台开发面试常见知识点总结(三)操作系统

静态链接库和动态链接库的区别 一个进程可以通过调用waitpid函数来等待它的子进程终止或者停止 Debug和Release的区别 临界区互斥量信号量事件进程互斥与同步 进程有哪几种状态,状态转换图,及导致转换的事件 进程由运行态进入就绪态和阻塞态的原因 进程切换 进程调度算法 死锁 哲学家就餐问题 linux运行时内存映像 通过虚拟地址访问内存的优势 缓存是数据交换的缓冲区(称为Cache) 线程访问某数据 无名管道  FIFO(命名管道)消息队列信号量信号共享内存 1.    静态链接库和动

【hive】时间段为五分钟的统计

问题内容 今天遇到了一个需求,需求就是时间段为5分钟的统计.有数据的时间戳.对成交单量进行统计. 想法思路 因为数据有时间戳,可以通过from_unixtime()来获取具体的时间. 有了具体的时间,就可以用minute()函数获取对应数据所在的分钟.(minute()获取到的分钟为字符串,需要进行类型转换cast()) 那么怎么通过获取到的minute来进行分组呢? 想法 00 - 05 应该分到一组, 05 - 10 应该分到第二组,依次类推. 用minute 整除 5 的话, 00 - 0