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

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

前言:

一个系统中的进程是与其他进程共享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中,因为它们通常是由操作系统管理的,而且可能会因为转换表的更新而变得非常大,所以不适合包含在控制结构中。页表是在物理内存中,由操作系统的内存管理系统维护。

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

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

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

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

观察以下代码:

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

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

相关文章
|
2月前
麒麟系统mate-indicators进程占用内存过高问题解决
【10月更文挑战第7天】麒麟系统mate-indicators进程占用内存过高问题解决
294 2
|
3月前
|
存储 Linux 调度
深入理解操作系统:从进程管理到内存分配
【8月更文挑战第44天】本文将带你深入操作系统的核心,探索其背后的原理和机制。我们将从进程管理开始,理解如何创建、调度和管理进程。然后,我们将探讨内存分配,了解操作系统如何管理计算机的内存资源。最后,我们将通过一些代码示例,展示这些概念是如何在实际操作系统中实现的。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
|
19天前
|
C语言 开发者 内存技术
探索操作系统核心:从进程管理到内存分配
本文将深入探讨操作系统的两大核心功能——进程管理和内存分配。通过直观的代码示例,我们将了解如何在操作系统中实现这些基本功能,以及它们如何影响系统性能和稳定性。文章旨在为读者提供一个清晰的操作系统内部工作机制视角,同时强调理解和掌握这些概念对于任何软件开发人员的重要性。
|
18天前
|
Linux 调度 C语言
深入理解操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅,从进程管理的基本概念出发,逐步探索到内存管理的高级技巧。我们将通过实际代码示例,揭示操作系统如何高效地调度和优化资源,确保系统稳定运行。无论你是初学者还是有一定基础的开发者,这篇文章都将为你打开一扇了解操作系统深层工作原理的大门。
|
21天前
|
调度 开发者
核心概念解析:进程与线程的对比分析
在操作系统和计算机编程领域,进程和线程是两个基本而核心的概念。它们是程序执行和资源管理的基础,但它们之间存在显著的差异。本文将深入探讨进程与线程的区别,并分析它们在现代软件开发中的应用和重要性。
39 4
|
28天前
|
算法 调度 开发者
深入理解操作系统:从进程管理到内存分配
本文旨在为读者提供一个深入浅出的操作系统知识之旅,从进程管理的基础概念出发,探索内存分配的策略与技巧。我们将通过实际代码示例,揭示操作系统背后的逻辑与奥秘,帮助读者构建起对操作系统工作原理的直观理解。文章不仅涵盖理论知识,还提供实践操作的指导,使读者能够将抽象的概念转化为具体的技能。无论你是初学者还是有一定基础的开发者,都能在这篇文章中找到有价值的信息和启发。
|
1月前
|
算法 调度 C++
深入理解操作系统:从进程管理到内存分配
【10月更文挑战第42天】本文将带你进入操作系统的神秘世界,探索其核心概念和关键技术。我们将从进程管理开始,了解操作系统如何协调和管理多个程序的运行;然后,我们将深入研究内存分配,看看操作系统如何有效地分配和管理计算机的内存资源。通过这篇文章,你将获得对操作系统工作原理的深入理解,并学会如何编写高效的代码来利用这些原理。
|
1月前
|
Linux
如何在 Linux 系统中查看进程占用的内存?
如何在 Linux 系统中查看进程占用的内存?
|
2月前
|
缓存 算法 调度
深入浅出操作系统:从进程管理到内存优化
本文旨在为读者提供一次深入浅出的操作系统之旅。我们将从进程管理的基本概念出发,逐步深入到内存管理的复杂世界,最终探索如何通过实践技巧来优化系统性能。文章将结合理论与实践,通过代码示例,帮助读者更好地理解操作系统的核心机制及其在日常技术工作中的重要性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你打开一扇通往操作系统深层次理解的大门。
|
3月前
|
监控 算法 Java
深入理解Java中的垃圾回收机制在Java编程中,垃圾回收(Garbage Collection, GC)是一个核心概念,它自动管理内存,帮助开发者避免内存泄漏和溢出问题。本文将探讨Java中的垃圾回收机制,包括其基本原理、不同类型的垃圾收集器以及如何调优垃圾回收性能。通过深入浅出的方式,让读者对Java的垃圾回收有一个全面的认识。
本文详细介绍了Java中的垃圾回收机制,从基本原理到不同类型垃圾收集器的工作原理,再到实际调优策略。通过通俗易懂的语言和条理清晰的解释,帮助读者更好地理解和应用Java的垃圾回收技术,从而编写出更高效、稳定的Java应用程序。