目录

1.介绍

2.理解

3.Linux早期的内核调度队列


1.介绍

这是32位的程序空间地址图:

为了更好地理解这段图,我们来写一段代码编译运行:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int g_val=100;int main()
{pid_t id = fork();int cnt=3;if(id == 0){while(1){printf("I am child, pid=%d, ppid=%d,g_val=%d &g_val=%p\n", getpid(), getppid(),g_val,&g_val);sleep(2);cnt--;if(cnt==0){g_val=500;printf("I am child,change pid=%d->%d\n", 100,500);}}}else {while(1){printf("I am father, pid=%d, ppid=%d,g_val=%d &g_val=%p\n", getpid(), getppid(),g_val,&g_val);sleep(2);}}return 0;
}

我们可以看见子进程修改 g_val 的地址后,父进程的地址和子进程的地址是一模一样的,一个地址为什么会有两个不同的值?

答案是这是个虚拟地址,不是物理内存地址,我们在用C/C++语言所看到的地址,全部都是虚拟地址!物理地址,用户一概看不到,由OS统一管理,下面我们从操作系统来理解地址空间

地址空间的本质是内核中的结构体对象。

未写时拷贝(初始共享)

父进程 fork 创建子进程,虚拟地址空间、页表 “逻辑复制” :父子进程虚拟地址(如 g_val 地址 0x56ab5ceac010 )一致,页表均映射到物理内存同一块数据页(g_val = 100 )。此时代码、数据物理页共享,不实际拷贝内存,快速创建进程,节省空间。

写时拷贝(触发拷贝)

当子 / 父进程尝试修改共享数据(如子进程改 g_val值 ),操作系统检测到写操作:
为写操作进程(如子进程)新分配物理页;
把原共享物理页数据(100 )拷贝到新页;
更新写操作进程页表,使其指向新物理页(此时子进程 g_val 500 )。父进程页表不变,仍访问原物理页(g_val 保持 100 ),实现 “写时才真正拷贝内存”,避免冗余开销
核心逻辑:读共享,写拷贝,平衡进程创建效率与数据独立性 。

2.理解

1.地址空间的本质是 struct 里面的一个结构体,内部很多属性都是表示 start end 的范围。 

2.虚拟地址无序变为有序,让进程从统一的角度看待物理内存以及自己运行的各个区域。

3.进程管理模块内存管理模块相互解耦。

在计算机系统(尤其是操作系统、分布式框架)中,进程管理模块(负责进程的生命周期管理、调度、状态维护、权限控制等)与内存管理模块(负责内存分配、回收、地址映射、虚拟内存管理等)是核心功能模块。

二者的 “相互解耦” 是指通过设计隔离模块间的直接依赖,使它们能独立完成各自功能,仅通过标准化接口协作,从而提升系统的可维护性、扩展性和容错性。

虚拟地址页表是实现两者解耦的核心机制之一

4.拦截非法请求

虚拟地址页表通过地址合法性验证权限检查进程地址空间隔离,构建了一层硬件级别的保护机制。它能有效拦截非法的内存访问请求(如越界、权限违规、访问未分配内存等),防止物理内存被错误或恶意操作破坏,是操作系统保障内存安全的核心手段之一。

之前我们介绍 Linux 进程的时候讲过一段代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");return 1;} else if (pid == 0) {while(1){printf("Child process: ID=%d PID = %d, PPID = %d\n", pid , getpid(), getppid());sleep(2);}} else {while(1){printf("Parent process: ID=%d PID = %d, Child PID = %d\n",pid , getpid(), pid);sleep(2);}}return 0;
}

fork() 对子进程进行了写时拷贝,所以才返回了两个不同的值。

3.Linux早期的内核调度队列

一个 CPU 拥有一个 runqueue

  • 如果有多个 CPU 就要考虑进程个数的负载均衡问题

运行队列优先级

queue[140]

之前我们介绍进程优先级的时候,我们介绍过进程默认优先级是 80,nice的范围为 [20,-19]。

进程队列的优先级为:

  • 普通优先级:100~139
  • 实时优先级:0~99

我们的进程值+40就能建立和进程队列的映射

位图:

long bitmap[ 5 ]

我们的队列优先级有140个,要是一个个逐一检测,会增加时间。

bitmap就是为了节约时间的 long bitmap[5] 有 32*5=160 足够包含这么多的优先级,我们只要看位图的数字就能找到哪个优先级还存在进程。

这就是大 O (1) 调度算法大 O (1) 调度算法指的是无论输入规模(比如进程数量、任务数量等)如何变化,算法执行所需的时间保持恒定,不随输入规模的增大而增加。

活动队列(Active Queue)(只出不进)

  • 作用:用于存放时间片尚未耗尽的进程,这些进程会依据优先级进行组织,系统优先调度优先级高的进程,以此保障系统能够高效响应任务需求。
  • 调度逻辑:利用 bitmap 快速查找出优先级最高的非空队列,然后选取该队列的队首进程执行。不管系统中进程的总数是多少,查找和调度进程所花费的时间始终固定,其时间复杂度为 O(1) ,确保了调度过程高效、稳定。

过期队列(Expired Queue)(只进不出)

  • 作用:用来存放时间片已经耗尽的进程,它的结构和活动队列完全一样,可看作是进程时间片管理的 “过渡区域”。
  • 特点:当活动队列中的进程把自身时间片用完后,就会被转移到过期队列中。而当活动队列为空(意味着所有进程的时间片都已耗尽 )时,系统会交换 active 和  expired 指针,此时过期队列就转变为新的活动队列,同时重新计算该队列中进程的时间片,让这些进程能够再次参与到系统调度中,以此实现 “批次轮换” 的调度机制,保障进程获取调度的公平性。

active 指针和 expired 指针

  • active 指针:始终指向当前可供调度使用的 活动队列,系统会从该队列里选取进程来执行任务。
  • expired 指针:始终指向 过期队列,用于暂时存放那些时间片已经耗尽的进程。
  • 核心机制:在系统运行过程中,活动队列里的进程会因为时间片不断消耗而逐渐减少,与之相对,过期队列里的进程数量会相应增多。当活动队列为空时,交换这两个指针,过期队列就 “变身” 为新的活动队列,原本过期队列中的进程会重新获得时间片,继续参与系统调度。这种方式无需实际去搬运进程,就能瞬间重置调度资源池,保障调度持续高效地进行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/918936.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/918936.shtml
英文地址,请注明出处:http://en.pswp.cn/news/918936.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

**标题:发散创新之力,探索隐私计算的未来**隐私计算,作为当下数字化时代的热门话题,正受

标题&#xff1a;发散创新之力&#xff0c;探索隐私计算的未来 隐私计算&#xff0c;作为当下数字化时代的热门话题&#xff0c;正受到越来越多开发者和从业者的关注。本文将带您走进隐私计算的奇妙世界&#xff0c;探讨其背后的技术原理、应用场景以及发展趋势。 一、隐私计算…

线程P5 | 单例模式[线程安全版]~懒汉 + 饿汉

什么是单例模式&#xff1f;在我们正式讲解单例模式之前&#xff0c;没有了解过的小伙伴可能会有疑问...到底啥叫单例模式&#xff1f;&#xff1f;其实单例模式呢&#xff0c;是我们设计模式中的一种&#xff0c;所谓的设计模式&#xff0c;你可以把它理解为一个模板&#xff…

kubernetes中数据存储etcd

etcd 在 Kubernetes 中的角色核心定位&#xff1a;Kubernetes 的 唯一持久化数据存储&#xff08;一致性数据库&#xff09;。职责&#xff1a; 保存整个集群的期望状态&#xff08;desired state&#xff09;&#xff0c;包括节点信息、Pod 清单、Service 定义、ConfigMap、Se…

Linux crontab定时任务

参考资料 【図解】cronの仕組み定时任务 - crontab解决ubuntu下定时任务不执行问题crontab环境变量问题&#x1f4a5;Linux定时任务功能详解&#xff1a;crontab与at命令应用指南 目录一. 环境准备1.1 wsl开启systemd1.2 开启cron日志二. cron服务管理相关命令2.1 service 的方…

企业频繁收到软件律师函?如何彻底解决这一难题

1. 引言&#xff1a;律师函频发&#xff0c;已成信息化管理的“隐形雷区”在工业制造、芯片、航空航天、船舶制造、医疗器械等高要求行业&#xff0c;软件不仅是研发与生产的关键工具&#xff0c;更是企业数据与知识产权安全的“底座”。然而&#xff0c;不少企业却在日常运营中…

在 macOS 上顺利安装 lapsolver

一、什么是 lapsolver&#xff1f; lapsolver 是一个用于求解线性分配问题&#xff08;Linear Assignment Problem, LAP&#xff09; 的 Python 库。线性分配问题是运筹学中的经典问题&#xff0c;核心是在两个集合&#xff08;如“工人”与“任务”&#xff09;之间找到一组最…

宋红康 JVM 笔记 Day02|JVM的架构模型、生命周期、发展历程

一、今日视频区间 P13-P25 二、一句话总结 JVM的架构模型&#xff1b;JVM的生命周期&#xff1b;JVM发展历程&#xff1b; 三、关键图/命令 3.1 JVM的架构模型Java程序对.class字节码文件进行反编译操作&#xff1a;在idea中先运行需要反编译的代码&#xff0c;找到对应的字节码…

Linux新手上路 | 在Ubuntu上Pluma文本编辑器的安装与基本使用

Linux新手上路 | 在Ubuntu上Pluma文本编辑器的安装与基本使用一、Pluma工具介绍1.1 Pluma 工具概述1.2 主要功能1.3 适用场景二、安装Pluma2.1 安装方法2.2 启动Pluma工具三、汉化方法3.1 安装汉化包3.2 设置系统语言3.3 重新打开Pluma四、基本使用方法4.1 编写文本内容4.2 关键…

React 揭秘:从新手到高手的进阶之路

目录 React&#xff1a;前端开发新宠​ React 初相识​ 什么是 React​ React 的核心特性​ 1.组件化开发 2.虚拟 DOM 与 Diff 算法 单向数据流 搭建 React 开发环境 环境准备​ 创建 React 项目 项目结构解析 React 基础语法与核心概念 JSX 语法​ 基本语法规则…

八股文小记 Servlet 过滤器-Spring MVC 拦截器-Spring AOP 拦截器区别

您对执行机制的洞察非常准确&#xff01;让我们深入分析这三种组件的调用机制及其与 AOP 节点的关系&#xff1a; 一、执行机制的本质区别组件调用机制实现原理Servlet 过滤器递归调用通过 FilterChain.doFilter() 显式递归调用下一个节点Spring MVC 拦截器遍历调用由 HandlerE…

qml 实现数值键盘

import QtQuick 2.0import QtQuick.Layouts 1.12 import"../pad" // PasswordKeyboard.qml import QtQuick 2.12ColumnLayout {id: keyboardspacing: 8// 键盘标题Text {text: "安全输入"font.pixelSize: 16color: "#666"Layout.alignment: Qt.A…

PID控制算法

文章目录引言一、基本原理1.1.简介1.2.开环与闭环1.3.PID 的公式1.3.1.比例项&#xff08;Proportional&#xff09;1.3.2.积分项&#xff08;Integral&#xff09;1.3.3.微分项&#xff08;Differential&#xff09;1.4.连续形式与离散形式的 PID 公式1.4.1.连续形式1.4.2.离散…

MyBatis 动态数据源切换在 Spring Boot 环境下的实现方案

第一章 需求背景与技术选型1.1 多数据源场景概述在大型企业级应用中&#xff0c;单一数据库往往无法满足高并发和多业务线的需求&#xff0c;因此需要引入 多数据源 的架构设计。常见的多数据源场景包括&#xff1a;读写分离、多租户、分库分表以及数据源负载均衡等。读写分离&…

PCA降维理论详解

文章目录一、什么是PCA&#xff1f;二、为什么需要降维&#xff1f;三、PCA的数学原理与详细推导视角一&#xff1a;最大化投影方差&#xff08;Maximizing Variance&#xff09;视角二&#xff1a;最小化重构误差&#xff08;Minimizing Reconstruction Error&#xff09;四、…

Android RxJava变换操作符详解

RxJava作为响应式编程在Android开发中的利器&#xff0c;其强大的变换操作符能够帮助我们优雅地处理数据流。本文将深入讲解RxJava中最常用的变换操作符及其实际应用场景。一、RxJava变换操作符概述变换操作符(Transformation Operators)用于对Observable发射的数据序列进行变换…

开源数据发现平台:Amundsen 快速上手指南

Amundsen 是一个数据发现和元数据引擎&#xff0c;旨在提高数据分析师、数据科学家和工程师与数据交互时的生产力。目前&#xff0c;它通过索引数据资源&#xff08;表格、仪表板、数据流等&#xff09;并基于使用模式&#xff08;例如&#xff0c;查询频率高的表格会优先于查询…

【密码学实战】国密SM2算法介绍及加解密/签名代码实现示例

引言 在信息安全领域&#xff0c;密码算法是数据保护的核心基石。2010 年&#xff0c;中国国家密码管理局发布了 SM2 椭圆曲线公钥密码算法&#xff0c;作为国产密码标准的核心成员&#xff0c;它凭借高效安全的特性&#xff0c;逐步替代 RSA 等国际算法&#xff0c;广泛应用于…

QT开发中如何加载第三方dll文件

文章目录&#x1f527; 一、隐式加载&#xff08;静态链接&#xff09;操作步骤&#xff1a;⚙️ 二、显式加载&#xff08;动态链接&#xff0c;推荐使用QLibrary&#xff09;操作步骤&#xff1a;&#x1f4bb; 三、直接调用Windows API&#xff08;仅Windows&#xff09;⚠️…

后端学习资料 持续更新中

数据库&#xff1a; 该网址包含&#xff1a;图解MySql&#xff0c; 看明白谁也问不倒你~ 图解计算机网络、操作系统、计算机组成、MySQL、Redis&#xff0c;让天下没有难懂的八股文&#xff01;https://xiaolincoding.com/

《嵌入式Linux应用编程(六):并发编程基础:多进程exec函数族及多线程基础》

一、exec函数族在一个进程里面执行另一个文件本质&#xff1a;将文本区的指令代码替换成exec要执行的指令#include <unistd.h>参数&#xff1a;path:要执行的可执行文件的路径和名称arg:执行该可执行文件时需要传递的参数NULL&#xff1a;参数传递结束标志 返回值&#x…