站得高,望得远

news2024/10/6 12:17:09

1、站得高,望的远

        计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决。

        这句话几乎概括了计算机系统软件体系结构的设计要点 ,整个体系结构从上到下都是按照严格的层次结构设计的。不仅是计算机系统软件整个体系是这样的,体系里面的每个组件比如操作系统本身,很多应用程序,软件系统甚至硬件结构都是按照这种层次的结构组织和设计的。系统软件体系结构中,各种软件的位置如图1所示。

图1 计算机软件体系结构 

        每个层次之间都需要相互通信,既然需要通信就必须有一个通信的协议,我们一般都将其称为接口,接口的下面那层是接口的提供者,由它定义接口;接口的上面那层是接口的使用者,它使用该接口来实现所需要的功能。在层次体系中,接口是被精心设计过的,尽量保持稳定不变,那么理论上层次之间只要遵循这个接口,任何一个层都可以被修改或被替换。除了硬件和应用程序,其他都是所谓的中间层,每个中间层都是对它下面的那层的包装盒扩展。正是这些中间层的存在,使得应用程序和硬件之间保持相对的独立。

        我们的软件体系中,位于最上层的是应用程序,比如我们平时用到的是网络浏览器,Email等。从整个层次结构上来看,开发工具与应用程序是属于同一个层次的。因为它们都使用一个接口,那就是操作系统应用程序编程接口(Application Programming Interface)。应用程序接口的提供者是运行库,什么样的运行库提供什么样的API,比如Linux下的Glibc库提供POSIX的API;Windows的运行库提供Windows API。

        运行库使用操作系统提供的系统调用接口,系统调用接口在实现中往往以中断的方式提供,Linux使用0x80号中断作为系统调用接口。

        操作系统内核层对于硬件层来说是硬件接口的使用者,而硬件是接口的定义者,硬件的接口决定了操作系统内核,具体来讲就是驱动程序如何操作硬件,如何与硬件进行通信。

2、操作系统做什么

        操作系统的一个功能是提供抽象的接口,另外一个主要功能是管理硬件资源。

        操作系统接管了所有的硬件资源,并且本身运行在一个受硬件保护的级别。所有的应用程序都以进程的方式运行在比操作系统权限更低的级别,每个进程都有自己独立的地址空间,使得进程之间的地址空间相互隔离。CPU由操作系统统一进行分配,每个进程根据进程优先级的高低都有机会得到CPU,但是,如果运行时间超出了一定的时间,操作系统会暂停该进程,将CPU的资源分配给其他等待运行的进程。

        操作系统作为硬件层的上层,它是对硬件的管理和抽象。对于操作系统上面的运行库和应用程序来说,它们希望看到的是一个统一的硬件访问模式。作为应用程序的开发者,我们不希望在开发应用程序的时候直接读写硬件接口,处理硬件中断等这些繁琐的事情。由于硬件之间千差万别,他们的操作方式和访问方式都有区别。比如我们希望在显示器上画一条直线,对于程序员来说,最好的方式是不管计算机使用的是什么显卡,什么显示器,多少大小多少分辨率,我们都只要调用统一的LineTo函数,具体的实现方式由操作系统来完成。

3、内存不够怎么办

        进程的总体目标是希望每个进程从逻辑上来看都可以独占计算机的资源。操作系统的多任务功能使得CPU能够在多个进程之间很好的共享,从进程的角度看好像是它独占了CPU而不用考虑与其他进程分享CPU的事情。操作系统的I/O抽象模型也很好的实现了I/O设备的共享和抽象,剩下的就是内存的分配问题了。

        在早期的计算机中,程序是直接运行在物理内存上的,也就是说,程序在运行时所访问的地址都是物理地址。当然,如果一个计算机同时只允许一个程序,那么只要程序要求的内存空间不要超过物理内存的大小,就不会有问题。但事实上为了更有效的利用硬件资源,我们必须同时运行多个程序,那么如何将计算机上有限的物理内存分配给多个程序使用。

        假设我们的计算机有128M的内存,程序A运行需要10MB,程序B需要100MB,程序C需要20MB。如果我们需要同时运行程序A和B,那么比较直接的做法是将内存的前10MB分配给程序A,10MB-110MB分配给B,这样就能够实现A和B两个程序同时运行,但这种简单的内存分配策略问题很多:

        1、地址空间不隔离:所有程序都直接访问物理地址,程序所使用的内存空间不是相互隔离的。恶意的程序可以很容易改写其他程序的内存数据,以达到破坏的目的;有些非恶意的,但是有臭虫的程序可能不小心修改了其他程序的数据,就会使其他程序也会崩溃,这对于需要安全稳定的计算环境的用户来说是不可容忍的。用户希望他在使用计算机的时候,其他一个任务失败了,至少不会影响其他任务。

        2、内存使用效率低:由于没有有效的内存管理机制,通常有一个程序执行时,监控程序就将整个程序装入内存中然后开始执行。如果我们忽然要运行程序C,那么这时候内存空间其实已经不够了,这时候我们可以用一个办法是将其他程序的数据暂时写到磁盘里面,等到要用的时候再读回来。由于程序所需要的空间是连续的,那么这个例子里面,如果我们将程序A换出到磁盘所释放的内存空间是不够的,所以只能将B换出到磁盘中,然后将C读入到内存中开始运行。可以看到整个过程中有大量的数据在换入换出,导致效率十分低下。

        3、程序运行的地址不确定:因为程序每次需要装入运行时,我们都需要给它从内存中分配一块足够大的空虚区域,这个空闲区域的位置是不确定的。这给程序的编写造成了一定的麻烦,因为程序在编写时,它所访问数据和指令跳转时的目标地址很多都是固定的,这涉及程序的重定位问题。

        解决这几个问题的思路就是使用我们之前提到过的法宝:增加中间层,即使用一种间接的地址访问方法。整个想法是这样的,我们把程序给出的地址看作是一种虚拟地址,然后通过某些映射的方法,将这个虚拟地址转换成实际的物理地址。这样,只要我们能够妥善的控制这个虚拟地址到物理地址的映射过程,就可以保证任意一个程序能够访问的物理内存区域跟另外一个程序相互不重叠,以达到地址空间隔离的效果。

        关于隔离

                让我们回到程序的运行本质上来。用户程序在运行时不希望介入到复杂的存储器管理过程中,作为普通程序,它需要的是一个简单的执行环节,有一个单一的地址空间,有自己的CPU,好像整个程序占有整个计算机而不关心其他的程序(当然程序间通信的部分除外,因为这是程序主动要求跟其他程序和联系)。地址空间分两种:虚拟地址空鹤物理地址空间。

                物理地址空间:实实在在存在的,存在于计算机中,而且对于每一台计算机来说只有唯一的一个,32位的处理器,计算机地址线有32条,那么物理空间最大就有4GB。

                虚拟地址空间:虚拟的,人们想象出来的地址空间,其实它并不存在,每个进程都有自己独立的虚拟空间,而且每个进程只能访问自己的地址空间,这样就有效的做到了进程的隔离。

        分段

                基本思想是把一段与程序所需要的内存空间大小的虚拟空间映射到某个地址空间。比如程序A需要10MB内存,那么我们假设有一个地址0x00000000到0x00A00000的10MB大小的一个假想的空间,也就是虚拟空间,然后我们从实际的物理内存中分配一个相同大小的物理地址,假设是物理地址0x00100000开始到0x00B0000结束的一块空间。然后我们把这两块相同大小的地址空间一一映射,即虚拟空间中的每个字节相对应与物理空间的每个字节。这个映射过程由软件来设置,比如操作系统来设置这个映射函数,实际的地址转换由硬件完成。比如当程序A中访问地址0x00001000时,CPU会将这个地址转换成实际的物理地址0x00101000。那么比如程序A和程序B在运行时,他们的虚拟空间和物理空间映射关系可能如图2所示

图2 段映射机制 

         分段的方法基本解决了上面提到的3个问题的第一个和第三个。首先它做到了地址隔离,因为程序A和程序B被映射到了两块不同的物理空间区域,它们之间没有任何重叠,如果程序A访问了虚拟空间的地址超出了0x00A0000这个范围,那么硬件就会判断这是一个非法的访问,拒绝这个地址请求,并将这个请求报告给操作系统或者监控程序,由它来决定如何处理。再者,对于每个程序来说,无论它们被分配到的物理地址的哪一个区域,对于程序来说都是透明的,他们不要关心物理地址的变化,它们只要按照从地址0x000000到0x00A00000来编写程序,放置变量,所以程序不再需要重定位。

                但是分段的这种方法还是没有解决我们的第二个问题,即内存使用效率的问题。分段对内存区域的映射还是按照程序为单位,如果内存不足,被换入换出到磁盘的都是整个程序,这样势必会造成大量的磁盘访问操作,从而严重影响速度,这种方法还是显着粗糙,粒度比较大。事实上,根据程序的局部性原理,当一个程序在运行时,在某个时间段内,它只是频繁的用到了一小部分数据,也就是说,程序的很多数据其实在一个时间段内都是不会被用到的。人们很自然的想到了更小颗粒度的内存分割和映射的方法,使得程序的局部性原理得到充分利用,大大提高了内存的使用率。这种方法就是分页。

        分页   

                分页的基本方法是把地址空间人为地等分成固定大小的页,每一页的大小由硬件决定,或硬件支持多种大小的页,由操作系统选择决定页的大小。比如Intel Pentium系列处理器执行4KB或者4MB的页大小,那么操作系统可以选择每页大小为4KB,也可以选择每页大小威4MB,但是在同一时刻只能选择一种大小。

                下面我们来看一个简单的例子。如图3所示,每个虚拟空间有8页,每页大小为1KB,那么虚拟地址空间就是8KB。我们假设该计算机有13条地址线,即拥有2^13的物理寻址能力,那么理论上物理空间可以达到8KB。但是出于种种原因,实际物理空间其实真正有效的只是前6KB。

                当我们把进程的虚拟地址空间按页分割,把常用的数据和代码页装载到内存中,把不常用的代码和数据保存在磁盘里,当需要用到的时候再把它从磁盘里取出来。以图3为例,我们假设有两个进程Process1和Process2,他们进程中的部分虚拟页面被映射到了物理页面,比如VP0,VP1和VP7映射到了PP0,PP2和PP3;而有部分页面却在磁盘中,比如VP2和VP3位于磁盘的DP0和DP1中;另外还有一些页面如VP4,VP5和VP6可能尚未被用到或访问到,它们暂停处于未使用的状态。在这里,我们把虚拟空间的页叫做虚拟页(VP,Virtual Page),把物理内存中的页叫做物理页(PP,Physical Page),把磁盘中的页叫做磁盘页(DP,Disk Page)。

                如3所示Process1的VP2和VP3不在内存中,但是当进程需要用到这两个页的时候,硬件会捕获到这个消息,就是所谓的页错误,然后操作系统接管进程,负责将VP2和VP3从磁盘中读出来并且装入内存,然后将内存中的这两个页与VP2与VP3之间建立映射关系。以页为单位来存取和交换这些数据非常方便,硬件本身就支持这种以页为单位的操作方式。

图3 进程虚拟空间,物理空间和磁盘之间的映射关系 

                保护野生页映射的目的之一,简单地说就是每个页可以设置权限属性,谁可以修改,谁可以访问等,而只有操作系统有权限修改这些属性。

                虚拟存储的实现需要依靠硬件的支持,对于不同的CPU来说是不同的,但是几乎所有的硬件都采用了一个叫做MMU(Memory ManagerMent Unit)的部件来进行页映射,如图4所示。在页映射模式下,CPU发出的是Virtual Address,即我们的程序看到的是虚拟地址。经过MMU转换以后就会变成Physical Address。

图4 虚拟地址到物理地址的转换 

        线程基础

                什么是线程

                        线程有时候被称为轻量级进程,是程序执行的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。通常意义上,一个进程由一个到多个线程组成,各个线程之间共享程序的内存空间(包括代码段,数据段,堆等)以及一些进程级的资源(如打开的文件和信号)。一个经典的线程与进程的关系如图5所示。

图5进程内的线程 

        

                多线程的优点:

                        1、某个操作可能陷入长时间等待,等待的线程会进入睡眠状态,无法继续执行。多线程执行可以有效利用等待的时间。典型的例子是等待网络响应,这可能要花费数秒甚至数十秒。

                        2、某个操作(常常是计算)会消耗大量的时间,如果只有一个线程,程序和用户之间的交互会中断。多线程可以让一个线程负责交互,另一个线程负责计算。

                        3、程序逻辑本身就要求并发操作,例如一个多端下载软件。

                        4、多CPU或多核计算机本身具备同时执行多个线程的能力,因此单线程程序无法全面地发挥计算机的全部计算能力。

                        5、相对于多进程应用,多线程在数据共享方面效率要高很多。

                线程的访问权限

                        线程的访问非常自由,它可以自由访问进程内存里的所有数据,甚至包括其他线程的堆栈(如果它知道其他线程的堆栈地址),但实际运用中线程也拥有自己的私有存储空间,包括以下几个方面。

                        1、栈(尽管并非完全无法被其他线程访问,但一般情况下仍然可以认为是私有数据)。

                        2、线程局部存储:是操作系统为线程单独提供的私有空间,但通常只具有很有限的容量。

                        3、寄存器(包括PC寄存器),寄存器是执行流的基本数据,因此是线程私有。

                        从C程序员的角度来看,数据在线程之间是否私有如表格所示

线程私有线程之间共享(进程所有)

局部变量

函数的参数

线程局部数据

全部变量

堆上的数据

函数里的静态变量

程序代码,任何线程都有权利读取并执行任何代码

打开的文件,A线程打开的文件可以由B线程读写

                线程调度与优先级

                        不论是在多处理器的计算机还是在单处理器的计算机上,线程总是“并发”执行的。当线程数量小于等于处理器数量时(并且操作系统支持多处理器),线程的并发是真正的并发,不同的线程运行在不同的处理器上,彼此之间互不相干。但对于线程数量大于处理器数量的情况,线程的并发会受到一些阻碍,因此此时至少有一个处理器会运行多个线程。

                        在单处理器对应多线程的情况下,并发是一种模拟出来的状态。操作系统会让这些多线程程序轮流执行,每次仅仅执行一小段时间(通常是几十到几百毫秒),这样每个线程就“看起来”在同时执行。这样的一个不断在处理器上切换不同的线程的行为称之为线程调用。在线程调用中,线程通常拥有至少三种状态,分别是:

                        1、运行:此时线程在执行

                        2、就绪:此时线程可以立刻运行,但CPU已经被占用

                        3、等待:此时线程正在等待某一事件(通常是I/O或同步)发生,无法执行

                        处于运行中线程拥有一段可以执行的时间,这段时间称为时间片,当时间片用尽的时候,该进程将进入就绪状态。如果在时间片用尽之前进程就开始等待某事件,那么它将进入等待状态。每当一个线程离开运行状态时,调用系统就会选择一个其他的就绪线程继续执行。在一个处于等待的线程所等待的事件发生之后,该线程将进入就绪状态。这3个状态的转移如图6所示。

线程状态切换 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

884. 两句话中的不常见单词 map与stringstream

目录 力扣884. 两句话中的不常见单词 【解法一】:最后写出了一坨屎,虽然它是一坨屎,但是它能动,虽然它是一坨屎,但起码这是我自己拉的 【大佬解法】 stringstream的使用 以及 map的使用 884. 两句话中的不常见单词 句…

python实现bib文件中参考文献的题目每个单词首字母大写

文章目录前言实现思路前言 由于毕业论文格式要求英文参考文献的题目的每个单词(除了介词)的首字母都要大写,如果一条条地自己修改费时费力,这里就想着简单地用python操作字符串的方式实现。 实现思路 观察bib参考文献格式&#x…

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核

20230102单独编译Toybrick的TB-RK3588X开发板的Android12的内核 2023/1/2 17:40 《RK3588_Android12_SDK_Developer_Guide_CN.pdf》 原厂的开发板rk3588-evb1-lp4-v10单独编译内核的方式: cd kernel-5.10 export PATH../prebuilts/clang/host/linux-x86/clang-r4161…

【数据结构】C语言实现链表(单链表部分)

目录 前言 链表 链表的分类 1.单向或者双向 2.带头或者不带头 3.循环或者非循环 单链表实现 定义节点 接口函数实现 创建节点 打印链表 尾插节点 尾删节点 头插节点 头删节点 单链表查找 删除指定位置后的节点 指定位置后插入节点 删除指定位置 指定位置插入节点…

Linux-7 文本编辑vivim

Linux-7 文本编辑vi/vim vim介绍 什么是vim? vi和vim是Linux下的一个文本编辑工具。(可以李姐为Windows的记事本或word文档) 为什么要使用vim? 因为Linux系统一切皆为文件,而我们工作最多的就是修改某个服务的配置&a…

一名七年老安卓的 2022 总结

大家好,我是 shixin。一转眼到了 2022 的最后一天,今年发生了很多事,这篇文章来总结一下。长短期目标达成情况和去年一样,我的长期目标是成为具备创业能力的人,包括商业思维和全栈技术能力。总的来说,今年是…

STM32MP157驱动开发——USB设备驱动

STM32MP157驱动开发——USB设备驱动一、简介1.电气属性2.USB OTG3.STM32MP1 USB 接口简介4.Type-C 电气属性二、USB HOST 驱动开发1.USB HOST 驱动编写2.配置 PHY 控制器3.配置usbh_ehci三、USB HOST 测试1.鼠标键盘驱动使能2.U盘驱动四、USB OTG驱动开发1.USB OTG 控制器节点信…

系统设计实战一

文章目录前言一、服务幂等1.防止订单重复下单1.1 场景如下:当用户在提交订单的时候1.2 重复下单解决方案1.3案例一幂等性总结2 防止订单ABA问题2.1 场景如下:当在修改订单用户信息的时候发生服务器或者网络问题导致的重试2.2 ABA问题解决方案2.3 业务ABA…

Mac本地安装Mysql并配置

文章目录一、安装Mysql二、配置Mysql三、启动mysql四、SQL语法初步了解1.创建数据库2.建表3.查看表一、安装Mysql 笔者推荐采用安装包的方法安装Mysql,比较简单,适合新手。 首先在网上搜安装包: baidu按关键字搜即可:mysql mac安…

多兴趣向量重构用户向量

Re4: Learning to Re-contrast, Re-attend, Re-construct for Multi-interest Recommendation 论文地址:https://arxiv.org/pdf/2208.08011.pdf 一般的多兴趣建模过程是对用户序列进行编码,抽取出用户的多个兴趣向量,然后利用这些用户兴趣向…

【Vue中使用Echarts】echarts初体验

文章目录一、echarts简介二、初次体验echarts1.下载2.在vue中引入echarts①全局引入(代码)② 局部引入一、echarts简介 在大数据盛行的今天,数据可视化变得越来越广泛。而在前端工作中,数据可视化用得最多的,可能就是…

Usaco Training 刷怪旅 第三层 第四题 :Combination Lock

一个六年级博主写文章不容易,给个关注呗 (点赞也行啊) 本蒟蒻的bilibili账号 注:这种题当你看不懂的时候是可以把题目复制去洛谷看中文版的 Farmer Johns cows keep escaping from his farm and causing mischief. To try and pre…

如何通过 Python 与 ChatGPT 对话

文章目录简介安装 OpenAI API实例1预备条件: 1. 科学上网; 2. 注册 OpenAI 账号。 简介 ChatGPT 是 GPT-3 语言模型的变体,专为会话语言生成而设计。要在 Python 中使用 ChatGPT,您需要安装 OpenAI API 客户端并获取 API 密钥。当前提你需要…

前端工程师leetcode算法面试必备-二分搜索算法(中)

一、前言 二分搜索算法本身并不是特别复杂,核心点主要集中在: 有序数组:指的是一个递增或者递减的区间(特殊情况如:【852. 山脉数组的峰顶索引】); 中间数:用来确定搜索目标落在左…

Pytorch学习笔记①——anaconda和jupyter环境的安装(小白教程)

一、安装Pytorch 1、首先找到anaconda命令端并点击进入。 2、输入如下命令创建子空间(博主的命名是pytorch1.4.0,使用python3.6版本) conda create -n pytorch1.4.0 python3.6对于下载速度慢的话,首先需要进行换源,换…

FastJson不出网rce

BCEL ClassLoader去哪了 0x01 BCEL从哪里来 首先,BCEL究竟是什么?它为什么会出现在JDK中? BCEL的全名应该是Apache Commons BCEL,属于Apache Commons项目下的一个子项目。Apache Commons大家应该不陌生,反序列化最著…

05 RS485

什么是RS485? RS485 是一种通用的通信标准,广泛用于数据采集和控制应用中。 它的主要优点之一是它允许将多个 RS485 设备放在同一条总线上,这使得多个节点可以相互连接。 RS-485(目前称为EIA/TIA-485)是通信物理层的…

面试官:React怎么做性能优化

前言 最近一直在学习关于React方面的知识,并有幸正好得到一个机会将其用在了实际的项目中。所以我打算以博客的形式,将我在学习和开发(React)过程中遇到的问题记录下来。 这两天遇到了关于组件不必要的重复渲染问题,…

2022 年,我身上发生的几件大事

一晃2022互联网寒冬年就要结束了,在今年我的身上发生了好几件人生大事。因为这些事情对我的心态、思绪等产生了不同层次、不同方面的影响,所以很有必要做一次年终复盘。那么,接下来让我用拙略的写作手法,带大家走进我那特别的2022…

别等iPhone14了,苹果iPhone15变化很大

在去年的手机市场当中,苹果可以说是最大的赢家。因为去年iPhone13发布的时间段,恰好是高端旗舰的空档期,小米、OV在高端市场的销量表现一般,华为又没有能力发布新机,三星的Note系列在去年也暂停发布。所以不夸张的说&a…