Linux之进程(四)(进程地址空间)

简介: Linux之进程(四)(进程地址空间)



一、程序地址空间

我们先来看看下面这张图。这张图是我们在学习语言时就见到过的内存区域划分图。

下面我们在Linux下看一看内存区域是不是也是这么划分的。

可见在Linux下也是符合上面的分布的。

那么下面我们来看看下面的代码:

上面的代码中用fork函数创建了一个子进程,其中让子进程相将全局变量g_val该从100改为200后打印,而父进程先休眠3秒钟,然后再打印全局变量的值。

按我们之前所学的来说子进程打印的全局变量的值为200,而父进程是在子进程将全局变量改后再打印的全局变量,而且全局变量在整个程序中应该只有一个,那么也应该是200,但是代码运行结果如下:

从上面的结果中,我们可以看到父进程打印的全局变量g_val的值为100,而子进程打印的是改变后的200。但是,更奇怪的是在父子进程中打印的全局变量g_val的地址是一样的,也就是说父子进程在同一个地址处读出的值是不同。

这就很奇怪了。同一个地址处却存的是不同的值,这和我们之前所学的知识又冲突了。同一个地址的值不应该是一样的吗?这到底是怎么回事呢?

最好的解释就是:在同一个地址处获取到的值却不同,这只能说明我们打印出来的地址绝对不是物理地址。 那是什么地址呢?

事实上,我们在语言层面上打印出来的地址都不是物理地址,而是虚拟地址。所以就算父子进程当中打印出来的全局变量的地址(虚拟地址)完全相同,但是两个进程当中全局变量的值却是不同的。因为每一个进程都有一个属于自己的地址空间!所以即使是地址名相同,也是在不同的地址空间中。

那么这就要求操作系统通过某种方式帮助用户将虚拟地址转换成物理地址。

二、进程地址空间

1、概念

所以之前说‘程序的地址空间’是不准确的,准确的应该说成 ’进程地址空间‘。我们所说的地址空间区域划分并不是对物理内存进行区域划分,而是对进程地址空间进行区域划分。

进程地址空间不是内存,其本质上是内存中的一种内核数据结构,在Linux当中进程地址空间具体由结构体mm_struct实现。所以对于进程地址空间的区域划分,本质上是定义每个区间的结束和开始。

在结构体mm_struct当中,各个边界之间的每一个部分都代表一个虚拟地址,这些虚拟地址通过页表映射与物理内存建立联系。

每个进程被创建时,其对应的进程控制块(task_struct)和进程地址空间(mm_struct)也会随之被创建。而操作系统可以通过进程的task_struct找到其对应的mm_struct,因为task_struct当中有一个结构体指针存储的是mm_struct的地址。

所以上面的代码结果我们就可以解释了。同一个变量,地址相同,其实是虚拟地址相同,内容不同其实是被页表映射到了不同的物理地址。

父子进程的进程地址空间当中的各个虚拟地址分别通过页表映射到物理内存的某个位置。

当子进程刚刚被创建时,子进程和父进程的数据和代码是共享的,即父子进程的代码和数据通过页表映射到物理内存的同一块空间。只有当父进程或子进程需要修改数据时,才将父进程的数据在内存当中重新开一块空间,拷贝一份,然后再进行修改。

这种在需要进行数据修改时再进行拷贝的方法,称为写时拷贝。

2、写时拷贝

~ 为什么要有写时拷贝?

进程具有独立性。多进程运行,需要独享各种资源,多进程运行期间互不干扰,不能让子进程的修改影响到父进程,也不能让父进程影响子进程。

~ 为什么不在创建子进程的时候就进行数据的拷贝?

子进程不一定会使用父进程的所有数据,并且在子进程不对数据进行写入的情况下,没有必要对数据进行拷贝,我们应该按需分配,在需要修改数据的时候再分配(延时分配),这样可以高效的使用内存空间。

写时拷贝是一种延时申请的技术,可以提高整机内存的使用率。

3、为什么要有进程地址空间

每一个进程都有自己的地址空间和页表,这样不仅麻烦而且理解成本也高,那么为什么要有虚拟地址?

~ 进程地址空间保证了数据的安全性

首先,我们先来看看如果我们直接使用物理内存会发生什么。如下图:我们在进程1中定义了一个指针char* ,因为我们现在是直接使用物理内存,所以char*直接指向了一个物理内存。如果我们进程1中的代码出现了错误,比如char* 指向了进程2中的地址,那么这样就会出问题,进程1的指针可以改变进程2的内容了。

所以操作系统不能让用户直接使用物理内存,于是就有了进程地址空间。

每个进程都有自己的进程地址空间,所有的进程都要通过页表映射到物理内存,而不同的进程会被映射到不同的物理内存中。万一进程越界非法访问、非法读写时,页表还可以进行拦截,不让其访问。而直接访问物理内存是无法拦截非法访问的,所以保证了内存数据的安全性。

~ 可以更方便的进行进程和进程的数据代码的解耦,保证了进程独立性

对于每一个进程而言,它们都有只属于自己的地址空间及页表,不同的进程通过页表映射到不同的物理内存上,所以一个进程数据的改变不会影响到另一个进程,保证了进程的独立性。可以做到物理内存分配和进程的管理之间不会相互影响。

~ 将内存分布有序化

因为在理论上,进程可以加载到物理内存的任意位置,所以在物理内存中几乎所有的代码和数据都是乱序的,而在进程地址空间中代码和数据的分布位置都是确定的。但是因为页表的存在,它可以将虚拟地址和物理地址进行映射,所以在进程的视角上,所有的内存分布都是有序的。

四、总结

其实,程序在编译时,编译器就会给每一个变量、每一个函数都编写一个地址,这个地址就是虚拟地址。当程序被加载到物理内存中,虚拟地址会被填写进页表的左侧。然后将一个代码加载到内存的什么位置的这个物理地址填写到页表的右侧。这就是映射关系的构建。

我们通常所说的地址,一般都是虚拟地址。而不是内存中的物理地址。

我们在语言中使用的new,malloc等申请的空间在本质上也都是申请的虚拟地址空间,而不是物理内存空间。而且申请了之后也不是直接拿到物理内存,只有当用户真正对物理地址空间进行访问的时候,才执行内存相关的管理算法,帮助用户从物理内存上申请空间,构建页表映射关系。然后用户再使用。

目录
相关文章
|
17天前
|
缓存 监控 Linux
linux进程管理万字详解!!!
本文档介绍了Linux系统中进程管理、系统负载监控、内存监控和磁盘监控的基本概念和常用命令。主要内容包括: 1. **进程管理**: - **进程介绍**:程序与进程的关系、进程的生命周期、查看进程号和父进程号的方法。 - **进程监控命令**:`ps`、`pstree`、`pidof`、`top`、`htop`、`lsof`等命令的使用方法和案例。 - **进程管理命令**:控制信号、`kill`、`pkill`、`killall`、前台和后台运行、`screen`、`nohup`等命令的使用方法和案例。
51 4
linux进程管理万字详解!!!
|
8天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
47 8
|
16天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
52 4
|
17天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
19天前
|
消息中间件 存储 Linux
|
25天前
|
运维 Linux
Linux查找占用的端口,并杀死进程的简单方法
通过上述步骤和命令,您能够迅速识别并根据实际情况管理Linux系统中占用特定端口的进程。为了获得更全面的服务器管理技巧和解决方案,提供了丰富的资源和专业服务,是您提升运维技能的理想选择。
31 1
|
1月前
|
算法 Linux 调度
深入理解Linux操作系统的进程管理
【10月更文挑战第9天】本文将深入浅出地介绍Linux系统中的进程管理机制,包括进程的概念、状态、调度以及如何在Linux环境下进行进程控制。我们将通过直观的语言和生动的比喻,让读者轻松掌握这一核心概念。文章不仅适合初学者构建基础,也能帮助有经验的用户加深对进程管理的理解。
23 1
|
4月前
|
运维 关系型数据库 MySQL
掌握taskset:优化你的Linux进程,提升系统性能
在多核处理器成为现代计算标准的今天,运维人员和性能调优人员面临着如何有效利用这些处理能力的挑战。优化进程运行的位置不仅可以提高性能,还能更好地管理和分配系统资源。 其中,taskset命令是一个强大的工具,它允许管理员将进程绑定到特定的CPU核心,减少上下文切换的开销,从而提升整体效率。
掌握taskset:优化你的Linux进程,提升系统性能
|
4月前
|
弹性计算 Linux 区块链
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
167 4
Linux系统CPU异常占用(minerd 、tplink等挖矿进程)
|
3月前
|
算法 Linux 调度
探索进程调度:Linux内核中的完全公平调度器
【8月更文挑战第2天】在操作系统的心脏——内核中,进程调度算法扮演着至关重要的角色。本文将深入探讨Linux内核中的完全公平调度器(Completely Fair Scheduler, CFS),一个旨在提供公平时间分配给所有进程的调度器。我们将通过代码示例,理解CFS如何管理运行队列、选择下一个运行进程以及如何对实时负载进行响应。文章将揭示CFS的设计哲学,并展示其如何在现代多任务计算环境中实现高效的资源分配。