【进程概念】虚拟内存与页表简述

简介: 【进程概念】虚拟内存与页表简述

前言:

一个系统中的进程是与其他进程共享CPU和主存资源的。早期的PC使用物理寻址,而且诸如数字信号处理器、嵌入式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式。然而现代处理器使用的是一种称为虚拟寻址(virtual addressing)的寻址形式。

物理寻址和虚拟寻址

物理寻址:

CPU想要访问哪个地址就直接访问,中间没有翻译的过程。

虚拟寻址:

使用虚拟地址,CPU通过访问页表得到一个虚拟地址,这个虚拟地址在被送到内存之前需要先转换成物理地址。将一个虚拟地址转换成物理地址的过程我们叫做地址翻译。这个过程需要CPU中的内存管理单元(MMU) 的专用硬件来操作。页表的内容由操作系统管理。

虚拟内存

为了更加有效的管理内存并且减少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟内存(VM)。虚拟内存是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的私有地址空间

虚拟内存的意义:

1、它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保留活动区域,并根据需要在磁盘和主存之间来回的传送数据,高效的使用了主存。

2、它为每个进程提供了一致的地址空间,简化了内存管理。

3、它保护了进程的地址空间不被其他进程破坏。

以上是我们之前介绍的程序的地址空间,但是这是不准确的,应该称为进程的地址空间。

由于虚拟内存概念的引入,每一个进程都拥有一个一致的虚拟地址空间,这使得我们操作系统能以统一的视角来看待每一个进程。

进程的虚拟地址空间分为用户虚拟地址空间和内核虚拟地址空间,所以进程共享内核虚拟地址空间,但每个进程有独立的用户虚拟地址空间。在用户地址空间内,又划分出堆区、栈区、数据区等区域。

mm_struct结构体

实际上,在我们的task_struct(PCB)中,进程的整体虚拟地址空间是由一个结构体mm_struct来描述的,每一个进程的task_struct里面都有一个mm_struct类型的指针变量,指向的内容用来描述整个进程的虚拟内存。

mm_struct源码片段

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;                   
//参数的起始和结束,环境变量的起始和终点

页表

页表是一种特殊的数据结构,放在系统空间的页表区,存放逻辑页与物理页帧的对应关系。 每一个进程都拥有一个自己的页表,PCB表中有指针指向页表。 (百度百科)

页表本身并不直接包含在task_struct中,因为它们通常是由操作系统管理的,而且可能会因为转换表的更新而变得非常大,所以不适合包含在控制结构中。页表是在物理内存中,由操作系统的内存管理系统维护。

简单来说,页表存放实现虚拟地址和物理地址映射的一种数据结构,通过查询页表我们就能找到相对应的物理地址。

解释父子进程的虚拟地址以及页表的关系

当某一个创建一个子进程,除了拷贝各种资源外,子进程会拷贝(写时拷贝)一份父进程的页表,页表内容与父进程一致

由于写时拷贝的机制,当子进程想要修改某个物理地址上的内容时,系统会重新给子进程找一片空间。该空间上的内容与父进程的一致,子进程在此空间上做修改不影响父进程,并且系统会调整子进程页表的映射的物理空间,使得子进程页表的映射不发生冲突。

观察以下代码:

果然,虽然虚拟地址一样,但是父子进程的页表中映射的物理地址不一样。(开始的时候一样,但是由于子进程发生了写入操作,使得系统重新找了一个物理空间)

知道了页表的作用,我们也能知道为什么不允许数组越界访问,因为在查页表的时候根本就没找到所访问的虚拟地址,更别谈去访问物理地址了。这样一来,我们也能理解页表其实也起到了保护内存的作用。

相关文章
|
存储 Linux API
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
在计算机系统的底层架构中,操作系统肩负着资源管理与任务调度的重任。当我们启动各类应用程序时,其背后复杂的运作机制便悄然展开。程序,作为静态的指令集合,如何在系统中实现动态执行?本文带你一探究竟!
【Linux进程概念】—— 操作系统中的“生命体”,计算机里的“多线程”
|
消息中间件 存储 网络协议
从零开始掌握进程间通信:管道、信号、消息队列、共享内存大揭秘
本文详细介绍了进程间通信(IPC)的六种主要方式:管道、信号、消息队列、共享内存、信号量和套接字。每种方式都有其特点和适用场景,如管道适用于父子进程间的通信,消息队列能传递结构化数据,共享内存提供高速数据交换,信号量用于同步控制,套接字支持跨网络通信。通过对比和分析,帮助读者理解并选择合适的IPC机制,以提高系统性能和可靠性。
1915 14
|
10月前
|
Unix Linux
对于Linux的进程概念以及进程状态的理解和解析
现在,我们已经了解了Linux进程的基础知识和进程状态的理解了。这就像我们理解了城市中行人的行走和行为模式!希望这个形象的例子能帮助我们更好地理解这个重要的概念,并在实际应用中发挥作用。
203 20
|
9月前
|
存储 Linux Shell
Linux进程概念-详细版(二)
在Linux进程概念-详细版(一)中我们解释了什么是进程,以及进程的各种状态,已经对进程有了一定的认识,那么这篇文章将会继续补全上篇文章剩余没有说到的,进程优先级,环境变量,程序地址空间,进程地址空间,以及调度队列。
171 0
|
9月前
|
Linux 调度 C语言
Linux进程概念-详细版(一)
子进程与父进程代码共享,其子进程直接用父进程的代码,其自己本身无代码,所以子进程无法改动代码,平时所说的修改是修改的数据。为什么要创建子进程:为了让其父子进程执行不同的代码块。子进程的数据相对于父进程是会进行写时拷贝(COW)。
231 0
|
12月前
|
存储 Linux 调度
【Linux】进程概念和进程状态
本文详细介绍了Linux系统中进程的核心概念与管理机制。从进程的定义出发,阐述了其作为操作系统资源管理的基本单位的重要性,并深入解析了task_struct结构体的内容及其在进程管理中的作用。同时,文章讲解了进程的基本操作(如获取PID、查看进程信息等)、父进程与子进程的关系(重点分析fork函数)、以及进程的三种主要状态(运行、阻塞、挂起)。此外,还探讨了Linux特有的进程状态表示和孤儿进程的处理方式。通过学习这些内容,读者可以更好地理解Linux进程的运行原理并优化系统性能。
456 4
|
存储 算法 数据处理
进程基础:概念、状态与生命周期
进程是操作系统进行资源分配和调度的基本单位,由程序段、数据段和进程控制块(PCB)组成。线程是进程中更小的执行单元,能独立运行且共享进程资源,具有轻量级和并发性特点。进程状态包括就绪、运行和阻塞,其生命周期分为创建、就绪、运行、阻塞和终止阶段。
836 2
|
消息中间件 Linux
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
928 20
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
204 4