IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 操作系统笔记——Linux实战、Windows(持续更新) -> 正文阅读

[系统运维]操作系统笔记——Linux实战、Windows(持续更新)

Linux进程管理

Linux内核基于Minix编写,现在的都是Linux发行版,是内核的自定义。

现代操作系统允许一个进程有多个执行流,即在相同的地址空间中可执行多个指令序列。每个执行流用一个线程表示,一个进程可以有多个线程。

Linux具体实现比较特别,Linux中严格来说是没有线程的,而是使用轻量级进程实现对多线程应用程序的支持,一个轻量级进程就是一个线程。

本章内容:

在这里插入图片描述

Linux进程组成

进程有两种状态,用户态和核心态。

这两种状态的根本区别在于切换了段地址。用户态的时候用的是用户栈,而核心态用的是核心栈。

状态的切换以及进程的切换都需要保存信息,其中就用到进程描述符

在这里插入图片描述

task_struct结构如下,图中仅列出关键的几个部分,实际上有更多:

  1. thread_info是进程的关键信息,又叫小描述符

在这里插入图片描述

每个进程都在内存中有一个进程核心栈,其和thread_info是放在一起的,总共占2页空间,核心栈在一端,thread_info在另一端。

task_struct通过thread_info指针访问核心栈,核心栈通过thread_info反向访问task_struct,是双向的。

具体到操作系统,操作系统通过esp获取thread_info地址,然后通过thread_info获取task_struct(PCB),即操作系统通过esp获取PCB信息。尤其是进程刚从用户态切换到核心态时,其核心栈为空,只要将栈顶指针减去8k,就能得到thread_info结构的地址。

在这里插入图片描述

  1. 可运行状态=运行态+就绪态
  2. 阻塞态分的比较细,下面逐一列出:
  3. 可中断的等待状态:进程睡眠等待系统资源可用或收到一个信号后,进程被唤醒。
  4. 不可中断的等待状态:进程睡眠等待一个不能被中断的事件发生。如进程等待设备驱动程序探测设备的状态。
  5. 暂停状态;
  6. 跟踪状态 ;
  7. 僵死状态 ;
  8. 死亡状态

Linux进程链表

Linux的链表都是list_head类型列表

全局的链表有:

  1. 所有进程链表tasks:链表头是0号进程,双向链表
  2. 可运行进程(TASK_RUNNING)链表run_list:按照它们的优先级可构建140个可运行进程队列(系统有140个优先级,非常细致)
  3. 等待进程链表。互斥等待访问临界资源的进程;非互斥等待的进程,所有进程都被唤醒wait_queue_t

这两个链表,每一个PCB都有:

  1. 子进程链表children
  2. 兄弟进程链表sibling

pid实际上是一种哈希(TODO)

在这里插入图片描述

Linux进程控制

用户进程创建与撤销

Linux有三个创建进程的函数:

  1. fork。采用写时复制技术,复制全部资源,根据返回pid判断是否是子进程,不阻塞。
  2. vfork。共享资源,且阻塞父进程。
  3. clone。轻量级进程函数,用于实现Linux线程,可以选择共享哪些数据。

要想实现共享+并行,需要用fork+共享内存区+PV操作实现。

进程撤销:

  1. exit()系统调用只终止某一个进程/线程。
  2. exit_group()系统调用能终止整个线程组。

如果只将主进程exit,子进程保留,子进程就会变成孤儿进程。
此时会给孤儿分配养父,即init进程(1号,监控用户态进程),init进程定期会处理僵死的子进程。

0,1,2号进程

前面是用户空间进程的创建,内核有另一套函数。

内核空间的线程创建create_ kthread () / kthread_run()。内核里只有线程,因为内核本身就是root权限,不需要进行数据隔离。出于好听的原因,人们又喜欢把内核线程称作进程。

内核线程的任务一般是执行周期性执行的任务,如刷新磁盘高速缓存;交换出不用的页;维护网络连接等任务。相对的,用户线程高度自定义,不具有周期性。

  1. 0号进程是一切进程的根。0号进程就是一个内核线程,0号进程是所有进程的祖先进程,又叫idle进程或叫做swapper进程。每个CPU都有一个0号进程。
  2. 1号进程(init)是用户态进程的根。是由0号进程创建的内核线程init,负责完成内核的初始化工作。在系统关闭之前,init进程一直存在,它负责创建和监控在操作系统外层执行的所有用户态进程。
  3. 2号进程(kthreadd)负责创建内核线程。

使用ps查看进程信息。-eo自定义显示信息,显示pid,ppid,command信息。

可以看到,没有显示0号进程,而1号进程负责init任务与用户态进程创建,其父进程是0号进程,2号进程负责内核线程创建。这里显示的其他进程都是内核线程,任务各不相同,其父进程都是2号进程。

在这里插入图片描述

Linux进程切换

用户态进程之间可以切换。用户态进程到核心态也需要切换。这两种切换执行的思路类似:

这里需要注意,进程切换只能发生在核心态,毕竟用户怎么能掌握计算机运行的调度权呢?那问题来了,从核心态切到用户态很自然,那用户态怎么切到核心态呢?这就需要触发中断,发送一个信号给核心,然后核心再进行切换。

所以一个切换操作分如下流程:

  1. 需要先将用户态寄存器信息保存,送到核心栈
  2. 还有一些寄存器值被送到PCB的thread_struct 的 thread字段中(硬件上下文)
  3. 最后通过核心态进行进程切换,先切页目录表(换一个页目录段,换一个页表TODO),再切核心栈与硬件上下文(恢复寄存器)

Linux进程调度

Linux,无论是用户态还是核心态,都是可抢占的。
为了保证抢占的合理,需要搭配动态优先级

进程调度类型:

  1. 先进先出的实时进程,时间片轮转的实时进程。基本优先数为1~99,优先级较高,费时较少
  2. 普通的分时进程。分时进程和批处理进程的基本优先数为100~139

实时进程调度时机:

  1. 被抢占了。出现了更高优先级的实时进程
  2. 走不动了。进程执行了阻塞操作,或者干脆停止运行或被杀死
  3. 自愿放弃。进程调用了sched_yield()自愿放弃处理机
  4. 轮转的实时系统中,时间片用完。

进程调度需要用到特殊的数据结构,其实就是前面的进程链表,是一维数组runqueues(TODO,TODO到底是一维数组还是链表?)。

一个CPU有140级全局可运行进程链表。

在时间片轮转系统中,还可以再分两类,一类是活动进程链表,一类是过期进程链表,各有140个队列。当活动进程都过期后,过期进程才可运行。避免低优先级进程没有机会运行(进程饥饿)

刚开始优先级动态计算复杂度比较高,所以引入了公平调度算法。

在这里插入图片描述

内核同步

不同内核线程使用一个内核,所以对于互斥资源就需要进行同步控制。核心思路就是保证临界区的同一时间只对应一个内核控制路径(?TODO)

同步方法很多,不止有信号量。

在这里插入图片描述

Linux储存器管理

在这里插入图片描述

进程地址空间的管理

内核虚空间

32位机器的进程寻址空间为4G。

进程的私有空间是3G,剩下1G是内核虚空间。

1G虚拟空间的前896M对应物理内存的前896M。前896MB的物理地址等于内核虚地址减去0xc0000000(3G)后128MB的虚拟空间比较特殊,是固定的分区,与用户。

在这里插入图片描述

用户空间进程管理

注意,这里针对的是3G的内存空间,是进程管理。而核心都是线程,不存在下面的管理机制。

针对3G的用户空间,Linux的管理机制如下图:
看着比较庞大,我们大致捋一下,你可能现在看不懂,但是看完后面两个结构的具体描述再回来看也是OK的:

  1. 从右往左看:实际上,一个进程的虚拟内存逻辑上是连续的,分为若干个区域。每一个区域都有一个vm_area_struct对应,这些vm_area_struct是以链表结构+红黑树结构组织的。
  2. 从左往右看:一个进程PCB通过一个mm_struct对虚拟空间进行宏观管理
  3. mm_struct和vm_area_struct就像是总分的关系一样,具体有什么联系?mm_struct指向vm_area_struct链表的头结点,指向其红黑树的根节点。而每一个vm_area_struct里面都有一个指针指向同一个mm_struct,用于快速返回mm_struct。

在这里插入图片描述

vm_area_struct

struct vm_area_struct {
	struct mm_struct * vm_mm; 虚拟内存描述符,指向其对应的mm_struct
	unsigned long vm_start;      /*起始地址*/
	unsigned long vm_end;       /*结束地址*/
	struct vm_area_struct  *vm_next; /*单链表*/
	struct rb_node  vm_rb;         /*红-黑树*/
	struct file * vm_file;  映射文件时指向文件对象
	……
}

结构里同时有红黑树指针和链表指针,说明vm area struct是同时具有两种组织方式。

红黑树是一种特殊的平衡二叉树,满足红黑树规则的n节点树,高度最多为 2 × l o g ( n + 1 ) 2\times log(n+1) 2×log(n+1)

在这里插入图片描述

mm_struct

内核线程不拥有mm_struct(本身就是线程,mm struct是针对进程的) 。


struct task_struct
 {   // PCBstruct mm_struct  *mm;}

struct mm_struct {  
	struct vm_area_struct *mmap;  /*单向链*/
	struct rb_root  mm_rb;  /*指向红-黑树的根*/
	pgd_t  *pgd;                   	 /*指向页目录表*/
	atomic_t mm_users;	 /*次使用计数器*/
	atomic_t mm_count; 	 /*主使用计数器*/
	struct list_head mmlist;   //双向链表
	unsigned long start_code, end_code;  /*可执行代码所占用的地址区间*/
	……};

结构里有指向vm area struct链表的头指针,也有指向红黑树结构的指针。

说一下mm_users mm_count这两个计数器。

  1. mm_users记录共享mm_struct的轻量级进程数。初值为1(主线程),增加一个线程就+1(TODO)
  2. mm_count记录内核线程使用数。初值为0,mm若把mm_struct暂时借给一个内核线程使用,则mm_count值增1。

进程结束,mm_users和mm_count都为0时,这个mm_struct才能被释放。

物理内存管理

物理内存是连续的(假设4G)

页框0给bios用,从0x000a0000到0x000fffff(1M空间)给BIOS例程用。

Linux管理页框的时候,会跳过前1M的空间(BIOS空间,对应RAM)。剩下的页框,大小为4KB,每一个页框都有一个页框描述符,struct page。这些struct page以结构数组的形式放在mem_map数组中。

struct page

这个结构,mapcount是页框号。其余的字段,要注意private字段,和伙伴系统有关(后面)。还有mapping字段,和页高速缓存的核心数据结构,与文件的inode有关。

struct page {
	unsigned long flags;  /*页框状态标志P175*/
	atomic_t  _count;	 /*页框的引用计数*/
	atomic_t  _mapcount; /*页框号,可以索引到物理页框*/
	unsigned long private; /*空闲时由伙伴系统使用*/
	struct address_space *mapping;用于页高速缓存
	pgoff_t  index;  在页高速缓存中以页为单位偏移
	struct list_head lru; 链入活动页框链表或非活动..
	void *virtual;     /*页框所映射的内核虚地址*/
};

在这里插入图片描述

内存管理区

整个4G内存被分成3块zone:

  1. ZONE_DMA:包含低于16MB的常规内存页框。用于对老式的基于ISA设备的DMA支持。0~15MB
  2. ZONE_NORMAL:包含高于16MB且低于896MB的常规内存页框。16MB~895MB,内核可以直接访问,用虚拟地址-3G即可得到物理内存。
  3. ZONE_HIGHMEM:包含从896MB-4G的高端物理页框。内核不能直接访问,后128+3G需要通过页管理机制寻址。

也就是说,大部分内存区域仅仅被一个zone结构管理:

这个结构里又出现了伙伴系统。

struct zone {  
	unsigned long  free_pages;  空闲页框数
	struct per_cpu_pageset  pageset[NR_CPUS];
	/*每CPU页框高速缓存,以满足CPU对单个页框的请求p177*/
	struct free_area  free_area[11]; 
	/*伙伴系统中的11个空闲页框链表*/
	struct list_head active_list; /*活动页框链表,存放最近正被访问的页框*/
  	struct list_head inactive_list; /*非活动页框链表,存放最近未被访问的页框*/
	…….};

分区页框分配器与伙伴系统

free_area是11个长度的数组。对应 2 0 ? 2 10 2^0-2^{10} 20?210长度。有的程序会需要连续的物理空间,而这个数组就负责统计整个zone里的连续物理空间,记录在数组中。

具体来说,比如数组中的8号位,实际上是一个链表头指针。指向一个链表,每一个链表节点都是起始页框描述符,这意味着这个链表对应着n段长度为8的连续物理空间。

而这里也揭示了private有什么用,private表示的是2的幂,如果是4就是16长度,3就是8长度。

在这里插入图片描述

伙伴系统就是基于分区页框分配器的。

假设要请求一个具有8个连续页框的块,该算法先在8个连续页框块的链表中检查是否有,如果没有,就在16个连续页框块的链表中找,如果找到,就把这16个连续页框分成两等份,一份用来满足请求,另一份插入到具有8个连续页框块的链表中;

如果在16个连续页框块的链表中没有找到,就在更大的块链表中查找,比如32找到了,就先切16,插入到16链表中,然后再把剩下的再切,把8插入到8链表中,最后剩下的8个连续页框就分配出去。

回收的时候,会检查长度,如果长度从8变成16,就合并,插入16中。

slab小内存分配器

伙伴系统以页框为单位,分配大块内存。有一些file对象或者各种描述符需要大量的小内存,这就是slab分配器的作用。

slab分配器先批发一些连续页框常驻内存,构成高速缓冲区,缓冲区内部进行细粒度分配。常驻内存以空间换时间,减少了内存分配初始化销毁释放的代价。

slab分配器生成的每个高速缓存存储一种类型的对象。高速缓存由一连串的slab构成,每个slab包含了若干个同类型的对象。这种细粒度的切分也是slab的特点。

在这里插入图片描述

虚拟地址转换

从一个虚拟地址到最后的物理地址,要经过多级转换。

首先,通过段基址+段偏移,获得32位线性地址,然后将32位线性地址通过分页部件转换成物理地址。

在这里插入图片描述

无论是页目录表项还是页表项,结构都是一样的。一个页表项,不仅仅包含地址,还有很多字段:

传统的页表项字段且不说,虚拟内存的页表项增加了一些字段:

  1. 物理地址20位。
  2. Present。标志页表是否在内存中。
  3. Accessed访问位,用于页面置换算法。
  4. Dirty位,写操作标记位,用于交换。

在这里插入图片描述

盘交换区与页面置换

Linux中,有一个磁盘交换区。可以理解为内存与磁盘之间的一种缓存。交换区可以直接作为一个磁盘分区,这种交换区就只有一个子区(swap分区),也可以以文件形式存在,但是这种就会被切分为多个物理块(文件会被离散储存)。

盘交换区由若干页槽组成,页槽大小和内存的页大小对应,为4K。盘交换区的第一个页槽存放交换区的整体信息,其他页槽用于交换。发生交换的时候,内核尽量把换出去的页放在相邻页槽中,减少后续磁道寻道时间。

缺页中断发生在这些情况下:

  1. 没访问过。该页从未被进程访问过,且没有相应的内存映射。
  2. 访问过,但被交换到交换区了。该页已被进程访问过,但其内容被临时保存到磁盘交换区上。
  3. 休眠中。该页在非活动页框链表中。
  4. 被锁了。该页正在由其它进程进行I/O传输过程中,这种只能阻塞。

发生缺页中断时,会先去交换区找,交换区找不到就会去磁盘去调。

页面置换策略是LFU(Least Frequently Used)。注意这和LRU不同,R是Recently,而这个是Friquently,这个算法会统计最近调用一页的频数,频数最少的就被交换出去。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-11-05 00:57:57  更:2022-11-05 01:01:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:24:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码