操作系统

https://blog.csdn.net/justloveyou_/article/details/78304294

1. 进程、线程

1.1 进程

进程是具有一定功能的程序关于某个数据集合上的一次运行活动,是系统进行资源调度和分配的一个独立单位,实现了操作系统的并发。

保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己独立的地址空间,有自己的堆,上级挂靠单位是操作系统。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。


什么是多进程:

在同一时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这就是多任务,也就是多进程。

多进程的优点:

  1. 每个进程相互独立,不影响主程序的稳定性,一个进程崩了,也不会影响其他进程;
  2. 通过增加CPU,可以很容易扩充性能;
  3. 可以减少线程加锁、解锁的影响,极大提高性能。

多进程的缺点:

  1. 逻辑控制复杂,需要和主程序交互;
  2. 需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算,所以进程开销比较大;
  3. 最好是多进程和多线程结合,即根据实际的需要,每个CPU开启一个子进程,这个子进程开启多线程可以为若干同类型的数据进行处理。

进程有哪几种状态?

  • 就绪状态:进程已获得除处理机以外的所需资源,等待分配处理机资源;
  • 运行状态:占用处理机资源运行,处于此状态的进程数小于等于CPU数;
  • 阻塞状态: 进程等待某种条件,在条件满足之前无法执行。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fFOvwZbg-1602775942025)(C:\Users\vocyd\AppData\Roaming\Typora\typora-user-images\image-20200910120920054.png)]

1.2 线程

线程,有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,但是所有同属进程下线程共享进程所拥有的全部资源。

同一个进程中可以有多个线程,线程不能独立存在,必须依附于进程,一个进程至少有一个线程,如果只有一个线程,那就是程序本身。


什么是多线程:

进程内一个独立的、库调度的执行单元,是系统独立调度和分派CPU的基础单位。在单个程序中同时运行多个线程完成不同的工作,就是多线程。

多线程的优点:

  1. 无需跨进程边界;
  2. 程序逻辑和控制方式简单;
  3. 所有线程可以直接共享内存和变量等;
  4. 线程方式消耗的总资源比进程方式好。

多线程缺点:

  1. 每个线程与主程序共用地址空间,受限于2GB地址空间;
  2. 线程之间的同步和加锁控制比较麻烦;
  3. 一个线程的崩溃可能影响到整个程序的稳定性;
  4. 到达一定的线程数程序后,即使再增肌CPU也无法提升性能;
  5. 线程能提高的总性能优先,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU。

1.3 协程

协程,是一种比线程更加轻量级的存在,协程不是被操作系统内核所管理,而完全是由程序所控制(也就是在用户态执行)。这样带来的好处就是性能得到了很大的提升,不会像线程切换那样消耗资源。

子程序,或者称为函数,在所有语言中都是层级调用,比如A调用B,B在执行过程中又调用了C,C执行完毕返回,B执行完毕返回,最后是A执行完毕。所以子程序调用是通过栈实现的,一个线程就是执行一个子程序。子程序调用总是一个入口,一次返回,调用顺序是明确的。而协程的调用和子程序不同。

协程在子程序内部是可中断的,然后转而执行别的子程序,在适当的时候再返回来接着执行

协程拥有自己的寄存器上下文的栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。因此协程能保留上次调用时的状态,每次过程重入时,就相当于上一次调用的状态。

协程需要用户自己编写调度逻辑,对于CPU来说,协程其实就是单线程,CPU不需要考虑怎么去调度、切换上下文,这样就省去了CPU的切换开销,因此协程在一定程度上要好于多线程。


协程的优点:

  1. 无须线程上下文切换的开销,因为子程序切换不是线程切换,而是由程序自身控制,和多线程比,线程数量越多,协程的性能优势就越明显;
  2. 无须原子操作锁定及同步的开销,原子操作就死一个最小的操作;
  3. 方便切换控制流,简化编程模型;
  4. 高并发性、高扩展性、低成本;

协程的缺点:

  1. 无法利用多核资源:协程的本质就是单线程,它不能同时将单个CPU的多核用上,协程需要配合进程才能运行在多核CPU上;
  2. 进程堵塞操作会堵塞掉整个程序。

1.4 进程和线程的区别、联系

区别

  • 调度
    • 线程作为调度和分配的基本单位,用于保证程序的 实时性,实现进程内部的并发;
    • 进程作为拥有资源的基本单位,是对运行时程序的封装,实现了操作系统的并发;
  • 并发性不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行
  • 拥有资源进程是拥有资源的一个独立单位,线程不拥有系统资源,多个线程共享进程的内存,可以访问所隶属的进程的资源。进程所维护的是程序所包含的资源(静态资源), 如:地址空间,打开的文件句柄集,文件系统状态,信号处理handler等;线程所维护的运行相关的资源(动态资源),如:运行栈,调度相关的控制信息,待处理的信号集等
  • 系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。但是进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个进程死掉就等于所有的线程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些

联系

  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程
  • 资源分配给进程,同一进程的所有线程共享该进程的所有资源;
  • 处理机分给线程,即真正在处理机上运行的是线程
  • 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。

1.5 进程同步

https://blog.csdn.net/qq_36136497/article/details/82697128

多进程虽然提高了系统资源利用率和吞吐量,但是由于进程的异步性可能造成系统的混乱。进程同步的任务就是对多个相关进程在执行顺序上进行协调,使并发执行的多个进程之间可以有效的共享资源和相互合作,保证程序执行的可再现性。

1.5.1 信号量

我们用信号量及PV操作来实现进程的同步和互斥。PV操作属于进程的低级通信。

信号量(semaphore)的数据结构为一个值和一个指针,指针指向等待该信号量的下一个进程。信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量;当它的值小于0时,其绝对值表示等待使用该资源的进程个数。注意,信号量的值仅能由PV操作来改变。它是用于进程间传递信号的一个整数值。在信号量上只有三种操作可以进行:初始化,P操作(-)和V操作(+),这三种操作都是原子操作。P操作(-)可以用于阻塞一个进程,V操作(+)可以用于解除阻塞一个进程。


PV操作:

由P操作原语和V操作原语组成(原语是不可中断的过程),对信号量进行操作,具体定义如下:

  • P(S):①将信号量S的值减1,即S=S-1;
    ②如果S<0,则该进程继续执行;否则该进程置为等待状态,排入等待队列。
  • V(S):①将信号量S的值加1,即S=S+1;
    ②如果S>0,则该进程继续执行;否则释放队列中第一个等待信号量的进程。

利用信号量和PV操作实现进程互斥的一般模型:

进程P1 进程P2 …… 进程Pn
…… …… ……
P(S); P(S); P(S);
临界区; 临界区; 临界区;
V(S); V(S); V(S);
…… …… …… ……


注意:

  1. 每个程序中用户实现互斥的P、V操作必须成对出现,先做P操作,进临界区,后做V操作,出临界区。若有多个分支,要认真检查其成对性。
  2. P、V操作应分别紧靠临界区的头尾部,临界区的代码应尽可能短,不能有死循环。
  3. 互斥信号量的初值一般为1。

利用信号量和PV操作实现进程同步:
PV操作是典型的同步机制之一。用一个信号量与一个消息联系起来,当信号量的值为0时,表示期望的消息尚未产生;当信号量的值非0时,表示期望的消息已经存在。用PV操作实现进程同步时,调用P操作测试消息是否到达,调用V操作发送消息。
使用PV操作实现进程同步时应该注意:

  1. 分析进程间的制约关系,确定信号量种类。在保持进程间有正确的同步关系情况下,哪个进程先执行,哪些进程后执行,彼此间通过什么资源(信号量)进行协调,从而明确要设置哪些信号量。
  2. 信号量的初值与相应资源的数量有关,也与P、V操作在程序代码中出现的位置有关。
  3. 同一信号量的P、V操作要成对出现,但它们分别在不同的进程代码中。

1.5.2 管程

信号量机制功能强大,但使用时对信号量的操作分散,而且难以控制,读写和维护都很困难。因此后来又提出了一种集中式同步进程——管程。其基本思想是将共享变量和对它们的操作集中在一个模块中,操作系统或并发程序就由这样的模块构成。这样模块之间联系清晰,便于维护和修改,易于保证正确性。

从语言的角度看,管程主要有以下特性:

  1. 模块化。管程是一个基本程序单位,可以单独编译;
  2. 抽象数据类型。管程是中不仅有数据,而且有对数据的操作;
  3. 信息掩蔽。管程外可以调用管程内部定义的一些函数,但函数的具体实现外部不可见。

对于管程中定义的共享变量的所有操作都局限在管程中,外部只能通过调用管程的某些函数来间接访问这些变量。因此管程有很好的封装性。

为了保证共享变量的数据一致性,管程应互斥使用。 管程通常是用于管理资源的,因此管程中有进程等待队列和相应的等待和唤醒操作。在管程入口有一个等待队列,称为入口等待队列。当一个已进入管程的进程等待时,就释放管程的互斥使用权;当已进入管程的一个进程唤醒另一个进程时,两者必须有一个退出或停止使用管程。在管程内部,由于执行唤醒signal操作,可能存在多个等待进程(等待使用管程),称为紧急等待队列(管程内部的进程执行了wait),它的优先级高于入口等待队列,也就是说,如果紧急队列有进程,则唤醒里面的进程,否则唤醒入口队列的进程。

因此,一个进程进入管程之前要先申请,一般由管程提供一个enter过程;离开时释放使用权,如果紧急等待队列不空,则唤醒第一个等待者,一般也由管程提供外部过程leave。

管程内部有自己的等待机制。管程可以说明一种特殊的条件型变量:var c:condition;实际上是一个指针,指向一个等待该条件的PCB队列。对条件型变量可执行wait和signal操作:(联系P和V; take和give)。

wait©:若紧急等待队列不空,唤醒第一个等待者,否则释放管程使用权。执行本操作的进程进入C队列尾部;

signal©:若C队列为空,继续原进程,否则唤醒队列第一个等待者,自己进入紧急等待队列尾部。

经典的进程同步问题:生产者-消费者问题;哲学家进餐问题;


1.5.3 进程状态改变

  1. 就绪→执行:当前运行进程阻塞,调度程序选一个优先权最高的进程占有处理机;

处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。

  1. 执行→就绪:当前运行进程时间片用完;

处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。

  1. 执行→阻塞:当前运行进程等待键盘输入,进入了睡眠状态;

正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。

  1. 阻塞→就绪:I/O操作完成,被中断处理程序唤醒。

处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。


1.6 进程通信

https://www.cnblogs.com/zgq0/p/8780893.html

进程间通信主要包括 管道, 系统IPC(Inter-Process Communication,进程间通信,包括消息队列、信号量、共享存储),Socket。

  • 管道(Pipe):管道是一种半双工的通信方式,可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。

  • 命名管道(Named Pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令 mkfifo 或系统调用 mkfifo 来创建。

  • 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;Linux 除了支持 Unix 早期信号语义函数 signal 外,还支持语义符合 Posix.1 标准的信号函数 sigaction(实际上,该函数是基于 BSD的,BSD 为了实现可靠信号机制,又能够统一对外接口,用 sigaction 函数重新实现了 signal函数)。

  • IPC消息(Message)队列:消息队列是消息的链接表,存放在内核中并由消息队列标识符标识。包括 Posix 消息队列 system V 消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  • IPC共享内存:使得多个进程可以访问同一块内存空间,是最快的可用 IPC 形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。

  • IPC信号量(Semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。

  • 内存映射(Mapped Memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。

  • 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由 Unix 系统的 BSD 分支开发出来的,但现在一般可以移植到其它类 Unix 系统上:Linux 和 System V 的变种都支持套接字。


1.7 线程同步、通信

多线程的同步与互斥(互斥锁、条件变量、读写锁、自旋锁、信号量)

线程同步:

  1. 互斥量(互斥锁/mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。互斥对象和临界区(代码的一个区间)对象非常相似,只是其允许在进程间使用,而临界区只限制于同一进程的各个线程之间使用,但是更节省资源,更有效率。
  2. 信号量/semaphore:它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。Mutex互斥量可以说是semaphore在仅取值0/1时的特例
  3. 事件(信号):通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操作。允许一个线程在处理完一个任务后,主动唤醒另外一个线程执行任务。比如在某些网络应用程序中,一个线程如A负责侦听通信端口,另外一个线程B负责更新用户数据,利用事件机制,则线程A可以通知线程B何时更新用户数据。

线程通讯

由于多线程共享地址空间和数据空间,所以多个线程间的通信是一个线程的数据可以直接提供给其他线程使用,而不必通过操作系统(也就是内核的调度)。 线程间的通信目的主要是用于线程同步。所以线程没有像进程通信中的用于数据交换的通信机制。也就是说,线程的通讯与线程的同步一样。

  • 锁机制:
    • 互斥锁提供了以排他方式防止数据结构被并发修改的方法。
    • 条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
    • 读写锁允许多个线程同时读共享数据,而对写操作是互斥的。
  • 信号量机制:包括无名线程信号量和命名线程信号量。
  • 信号机制:类似进程间的信号处理。

1.9 操作系统的进程调度策略

  • FCFS(先来先服务,队列实现,非抢占的):先请求CPU的进程先分配到CPU。
  • SJF(最短作业优先调度算法):平均等待时间最短,但难以知道下一个CPU区间长度。
  • 优先级调度算法(可以是抢占的,也可以是非抢占的):优先级越高越先分配到CPU,相同优先级先到先服务,存在的主要问题是:低优先级进程无穷等待CPU,会导致无穷阻塞或饥饿;解决方案:老化。
  • 时间片轮转调度算法(可抢占的):队列中没有进程被分配超过一个时间片的CPU时间,除非它是唯一可运行的进程。如果进程的CPU区间超过了一个时间片,那么该进程就被抢占并放回就绪队列。
  • 多级队列调度算法:将就绪队列分成多个独立的队列,每个队列都有自己的调度算法,队列之间采用固定优先级抢占调度。其中,一个进程根据自身属性被永久地分配到一个队列中。
  • 多级反馈队列调度算法:与多级队列调度算法相比,其允许进程在队列之间移动:若进程使用过多CPU时间,那么它会被转移到更低的优先级队列;在较低优先级队列等待时间过长的进程会被转移到更高优先级队列,以防止饥饿发生。

2. 死锁

https://blog.csdn.net/bob_man/article/details/104363237

死锁是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

2.1 死锁条件

  • 互斥:至少有一个资源必须属于非共享模式,即一次只能被一个进程使用;若其他申请使用该资源,那么申请进程必须等到该资源被释放为止;
  • 占有并等待:一个进程必须占有至少一个资源,并等待另一个资源,而该资源为其他进程所占有;
  • 非抢占(无法剥夺的等待):进程不能被抢占,即资源只能被进程在完成任务后自愿释放;
  • 循环等待:若干进程之间形成一种头尾相接的环形等待资源关系。

2.2 处理策略

解决死锁的基本方法主要有 预防死锁、避免死锁、检测死锁、解除死锁 、鸵鸟策略等。

死锁预防

基本思想是只要确保死锁发生的四个必要条件中至少有一个不成立,就能预防死锁的发生,具体方法包括:

  • 打破互斥条件:允许进程同时访问某些资源。但是,有些资源是不能被多个进程所共享的,这是由资源本身属性所决定的,因此,这种办法通常并无实用价值。
  • 打破占有并等待条件:可以实行资源预先分配策略(进程在运行前一次性向系统申请它所需要的全部资源,若所需全部资源得不到满足,则不分配任何资源,此进程暂不运行;只有当系统能满足当前进程所需的全部资源时,才一次性将所申请资源全部分配给该线程)或者只允许进程在没有占用资源时才可以申请资源(一个进程可申请一些资源并使用它们,但是在当前进程申请更多资源之前,它必须全部释放当前所占有的资源)。但是这种策略也存在一些缺点:在很多情况下,无法预知一个进程执行前所需的全部资源,因为进程是动态执行的,不可预知的;同时,会降低资源利用率,导致降低了进程的并发性。
  • 打破非抢占条件:允许进程强行从占有者哪里夺取某些资源。也就是说,但一个进程占有了一部分资源,在其申请新的资源且得不到满足时,它必须释放所有占有的资源以便让其它线程使用。这种预防死锁的方式实现起来困难,会降低系统性能。
  • 打破循环等待条件:实行资源有序分配策略。对所有资源排序编号,所有进程对资源的请求必须严格按资源序号递增的顺序提出,即只有占用了小号资源才能申请大号资源,这样就不回产生环路,预防死锁的发生。

死锁避免
死锁避免的基本思想是动态地检测资源分配状态,以确保循环等待条件不成立,从而确保系统处于安全状态。所谓安全状态是指:如果系统能按某个顺序为每个进程分配资源(不超过其最大值),那么系统状态是安全的,换句话说就是,如果存在一个安全序列,那么系统处于安全状态。资源分配图算法和银行家算法是两种经典的死锁避免的算法,其可以确保系统始终处于安全状态。其中,资源分配图算法应用场景为每种资源类型只有一个实例(申请边,分配边,需求边,不形成环才允许分配),而银行家算法应用于每种资源类型可以有多个实例的场景。


死锁解除

死锁解除的常用两种方法为进程终止和资源抢占。

  • 进程终止是指简单地终止一个或多个进程以打破循环等待,包括两种方式:终止所有死锁进程和一次只终止一个进程直到取消死锁循环为止;

  • 资源抢占是指从一个或多个死锁进程那里抢占一个或多个资源,此时必须考虑三个问题:

    • 选择一个牺牲品;
    • 回滚:回滚到安全状态;
    • 饥饿(在代价因素中加上回滚次数,回滚的越多则越不可能继续被作为牺牲品,避免一个进程总是被回滚)。

2.3 活锁、饥饿

活锁

指线程1可以使用资源,但它很礼貌,让其他线程先使用资源,线程2也可以使用资源,但它很绅士,也让其他线程先使用资源。这样你让我,我让你,最后两个线程都无法使用资源。实例:消息队列。

原因:重试机制不变,消息队列始终重试,始终相互谦让。

解决:

  1. 以太网的指数退避算法(重试时间不固定);

  2. 加入随机因素;

  3. 放到队列尾部、重试限制。


饥饿

类似于非公平锁机制,多个线程在等待资源的时候,有一个很早就在等待的线程一直获取不到锁,反而让后面来的线程获得了锁。

  • 线程的优先级设置得过低,或者由于某线程持有锁同时又无限循环而不释放锁,或者某程序始终占用某文件的写锁
  • 饥饿可能会导致响应性差

3. 内存

3.1 内存管理

连续内存分配

  1. 首次适配:空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。
  2. 最优适配:空闲分区按容量递增形成*分区链*,找到第一个能满足要求的空闲分区。
  3. 最坏适配:空闲分区以容量递减的次序*链接*。找到第一个能满足要求的空闲分区,也就是挑选出最大的分区。

非连续内存分配

3.1.1 分页式存储管理

页式存储管理方案是一种用户视角内存与物理内存相分离的内存分配管理方案。在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的帧,程序加载时,可以将任意一页放入内存中任意一个帧,这些帧不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)。

  1. 基本思想:用户程序的地址空间被划分成若干固定大小的区域,称为“页”,相应地,内存空间分成若干个物理块,页和块的大小相等。可将用户程序的任一页放在内存的任一块中,实现了离散分配。
  2. 分页概念:逻辑空间分页,物理空间分块,页与块同样大,页连续块离散,用页号查页表,由硬件做转换,页面和内存块大小一般选为2的若干次幂(便于管理)。页表作用:实现从页号到物理地址的映射。
  3. 分页存储管理的地址机构:页号4位,每个作业最多2的4次方=16页,表示页号从00001111(24-1),页内位移量的位数表示页的大小,若页内位移量12位,则2的12次方=4k,页的大小为4k,页内地址从000000000000111111111111。
  4. 页表:分页系统中,允许将进程的每一页离散地存储在内存的任一物理块中,为了能在内存中找到每个页面对应的物理块,系统为每个进程建立一张页面映射表,简称页表。页表的作用是实现从页号到物理块号的地址映射。
  5. 具有快表的地址变换机构:分页系统中,CPU每次要存取一个数据,都要两次访问内存(访问页表、访问实际物理地址)。为提高地址变换速度,增设一个具有并行查询能力的特殊高速缓冲存储器,称为“联想存储器”或“快表”,存放当前访问的页表项,快表就是存放在高速缓冲存储器的部分页表。它起页表相同的作用。包含快表机制的内存管理中,当要访问内存数据的时候,首先将页号在快表中查询,如果查找到说明要访问的页表项在快表中,那么直接从快表中读取相应的物理块号;如果没有找到,那么访问内存中的页表,从页表中得到物理地址,同时将页表中的该映射表项添加到快表中(可能存在快表换出算法)。只需要一次内存访问
  6. 多级页表:在某些计算机中如果内存的逻辑地址很大,将会导致程序的页表项会很多,而页表在内存中是连续存放的,所以相应的就需要较大的连续内存空间。为了解决这个问题,可以采用两级页表或者多级页表的方法,其中外层页表一次性调入内存且连续存放,内层页表离散存放。相应的访问内存页表的时候需要一次地址变换,访问逻辑地址对应的物理地址的时候也需要一次地址变换,而且一共需要访问内存3次才可以读取一次数据。
  7. 如果存储器采用基本分页机制,那么操作系统会为每个进程或任务建立一个页表(这个页表可能是一级的也可能是多级的)。整个操作系统中有多个进程在运行,那么系统就会有多个页表。页表在内存中的存储位置由寄存器CR3给出。

分页系统中,CPU每次要存取一个数据,都要两次访问内存(访问页表、访问实际物理地址)。为提高地址变换速度,增设一个具有并行查询能力的特殊高速缓冲存储器,称为“联想存储器”或“快表”,存放当前访问的页表项。

请求分页的基本思想:

  1. 请求分页=分页+请求。
  2. 请求分页提供虚拟存储器。
  3. 页表项中的状态位指示该页面是否在内存,若不在,则产生一个缺页中断。

3.1.2 分段式存储管理

段式存储管理是一种符合用户视角的内存分配管理方案。在段式存储管理中,将程序的地址空间划分为若干段(Segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)。

  1. 基本思想:将用户程序地址空间分成若干个大小不等的段,每段可以定义一组相对完整的逻辑信息。存储分配时,以段为单位,段与段在内存中可以不相邻接,也实现了离散分配。
  2. 分段存储方式的引入:方便编程、分段共享、分段保护、动态链接、动态增长.
  3. 分段地址结构:作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。例程序段、数据段等。每个段都从0开始编址,段长不一样,并采用一段连续的地址空间。段的长度由相应的逻辑信息组的长度决定,因而各段长度不等。整个作业的地址空间是二维的。一维是段号,一维是(段内地址/段表项的长度);由于分段管理中,每个段内部是连续内存分配,但是段和段之间是离散分配的,因此也存在一个逻辑地址到物理地址的映射关系,相应的就是段表机制。段表中的每一个表项记录了该段在内存中的起始地址和该段的长度。段表可以放在内存中也可以放在寄存器中。
  4. 访问内存的次数:访问内存的时候根据段号和(段内地址/段表项的长度/段内位移量)计算当前访问段在段表中的位置,然后访问段表,得到该段的物理地址,根据该物理地址以及段内偏移量就可以得到需要访问的内存。由于也是两次内存访问,所以分段管理中同样引入了联想寄存器。
  5. 如果存储器采用基本分段机制,那么操作系统会为每个进程或任务建立一个段表段表由段号、段长、基址组成,用户通过段号到段表中获得段长与基址,从而定位到内存中的数据。内存空间中,每个段之间不连续,但是每个段自己内部是连续的。

3.1.3 分段、分页式区别

  • 目的不同:分页是由于系统管理的需要而不是用户的需要,它是信息的物理单位;分段的目的是为了能更好地满足用户的需要,它是信息的逻辑单位,它含有一组其意义相对完整的信息;
  • 大小不同:页的大小固定且由系统决定,而段的长度却不固定,由其所完成的功能决定;
  • 地址空间不同: 段向用户提供二维地址空间(段号+段内地址);页向用户提供的是一维地址空间(页号);
  • 信息共享:段是信息的逻辑单位,便于存储保护和信息的共享,根据用户的需要划分,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,为了实现非连续分配,以便解决内存碎片问题,或者说分页是由于系统管理的需要,其对用户是透明的,页的保护和共享受到限制;
  • 内存碎片:页式存储管理的优点是没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满);而段式管理的优点是没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片。

3.1.4 段页式

基本思想:

分页系统能有效地提高内存的利用率,而分段系统能反映程序的逻辑结构,便于段的共享与保护,将分页与分段两种存储方式结合起来,就形成了段页式存储管理方式。

在段页式存储管理系统中,作业的地址空间首先被分成若干个逻辑分段,每段都有自己的段号,然后再将每段分成若干个大小相等的页。对于主存空间也分成大小相等的页,主存的分配以页为单位。

段页式系统中,作业的地址结构包含三部分的内容:段号、页号、页内位移量;程序员按照分段系统的地址结构将地址分为段号与段内位移量,地址变换机构将段内位移量分解为页号和页内位移量。

为实现段页式存储管理,系统应为每个进程设置一个段表,包括每段的段号,该段的页表始址和页表长度(本来是段内基址和段长), 如果采用段页式结合的机制,那么一般一个进程或任务,操作系统会给其建立一个段表,而段表中的每个段又会对应一个页表,也就是说,段页式机制的每个进程有一个段表,有多个页表。

访问内存的次数:

在段页式系统中,为了获得一条指令或数据,须三次访问内存。第一次访问是访问内存中的段表,从中取得页表始址;第二次访问是访问内存中的页表,从中取出该页所在的物理块号,并将该块号与页内地址一起形成指令或数据的物理地址;第三次访问才是真正从第二次访问所得的地址中,取出指令或数据。

总结:将程序分为代码段、数据段、堆栈段便于存储管理(比如修改代码段的时候可以立马抛出异常);地址分为段号+偏移量,通过段号找到段的基址,和偏移量相加得到一个线性地址,这个线性地址再通过分页系统进行转换,最后形成物理地址。


3.2 内存泄漏

  • 内存溢出: out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;
    • 比如申请了一个integer,但给它存了long才能存下的数,发生内存溢出。
    • 要求分配的内存超出了系统能给你的,系统不能满足需求,于是产生溢出。
    • 比如栈,栈满时再做进栈必定产生空间溢出,叫上溢;栈空时再做退栈也产生空间溢出,称为下溢。就是分配的内存不足以放下数据项序列。
  • 内存泄露 :memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
    • memory leak会最终导致out of memory。
    • 向系统申请分配内存进行使用(new),可是使用完了以后却不归还(delete),结果申请到的那块内存自己也不能再访问(也许把它的地址给弄丢了),而系统也不能再次将它分配给需要的程序。

3.2.1 内存泄漏分类

从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到 。

  1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。

  2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。

  3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。

  4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。


3.2.2 Java内存泄漏

Java 内存分配策略

Java 程序运行时的内存分配策略有三种,分别是静态分配,栈式分配,和堆式分配。对应的,三种存储策略使用的内存空间主要分别是静态存储区(也称方法区)、栈区和堆区。

内存泄漏的原因

长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄漏,尽管短生命周期对象已经不再需要,但是因为长生命周期持有它的引用而导致不能被回收,这就是Java中内存泄漏的发生场景。具体主要有如下几大类:

  • 静态集合类引起内存泄漏

HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,他们所引用的所有的对象Object也不能被释放(即使这个object已经为null了),所以需要手动从集合类中删除

  • 当集合里面的对象属性被修改后,再调用remove()方法时不起作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z1jU4qcX-1602775942031)(C:\Users\vocyd\AppData\Roaming\Typora\typora-user-images\image-20200910152740276.png)]

  • 监听器

在Java 编程中,我们都需要和监听器打交道,通常一个应用当中会用到很多监听器,我们会调用一个控件的诸如addXXXListener()等方法来增加监听器,但往往在释放对象的时候却没有记住去删除这些监听器,从而增加了内存泄漏的机会。

  • 各种连接

比如数据库连接(dataSourse.getConnection()),网络连接(Socket)和IO连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的。对于Resultset 和Statement 对象可以不进行显式回收,但Connection 一定要显式回收,因为Connection 在任何时候都无法自动回收,而Connection一旦回收,Resultset 和Statement 对象就会立即为NULL。但是如果使用连接池,情况就不一样了,除了要显式地关闭连接,还必须显式地关闭Resultset Statement 对象(关闭其中一个,另外一个也会关闭),否则就会造成大量的Statement 对象无法释放,从而引起内存泄漏。这种情况下一般都会在try里面去的连接,在finally里面释放连接。

  • 内部类和外部模块的引用

内部类有个特性,是会持有一个外部类的引用。如果内部类的实例一直存活,那么外部类activity的实例也就一直在。

  • 单例模式

不正确使用单例模式是引起内存泄漏的一个常见问题,单例对象在初始化后将在JVM的整个生命周期中存在(以静态变量的方式),如果单例对象持有外部的引用,那么这个对象将不能被JVM正常回收,导致内存泄漏。


3.3 虚拟内存

内存的发展历程:

没有内存抽象(单进程,除去操作系统所用的内存之外,全部给用户程序使用)—>

有内存抽象(多进程,进程独立的地址空间,交换技术(内存大小不可能容纳下所有并发执行的进程)—>

连续内存分配(固定大小分区(多道程序的程度受限),可变分区(首次适应,最佳适应,最差适应),碎片) —>

不连续内存分配(分段,分页,段页式,虚拟内存)


背景

如果存在一个程序,所需内存空间超过了计算机可以提供的实际内存,那么由于该程序无法装入内存所以也就无法运行。单纯的增加物理内存只能解决一部分问题,但是仍然会出现无法装入单个或者无法同时装入多个程序的问题。但是可以从逻辑的角度扩充内存容量,即可解决上述两种问题。

基于局部性原理,在程序装入时,可以将程序的一部分装入内存,而将其余部分留在外存,就可以启动程序执行。在程序执行过程中,当所访问的信息不在内存时,由操作系统将所需要的部分调入内存,然后继续执行程序。另一方面,操作系统将内存中暂时不使用的内容换出到外存上,从而腾出空间存放将要调入内存的信息。这样,系统好像为用户提供了一个比实际内存大得多的存储器,称为虚拟存储器。


虚拟内存的基本思想:

虚拟内存允许执行进程不必完全在内存中,每个进程拥有独立的地址空间,这个空间被分为大小相等的多个块,称为页(Page),每个页都是一段连续的地址。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立刻进行必要的映射;当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令。这样,对于进程而言,逻辑上似乎有很大的内存空间,实际上其中一部分对应物理内存上的一块(称为帧,通常页和帧大小相等),还有一些没加载在内存中的对应在硬盘上,如图所示。

注意,请求分页系统、请求分段系统和请求段页式系统都是针对虚拟内存的,通过请求实现内存与外存的信息置换。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tVIT1HBv-1602775942033)(C:\Users\vocyd\AppData\Roaming\Typora\typora-user-images\image-20200910153128515.png)]


虚拟存储器的特征

多次性:一个作业可以分多次被调入内存。多次性是虚拟存储特有的属性。

对换性:作业运行过程中存在换进换出的过程(换出暂时不用的数据换入需要的数据)。

虚拟性:虚拟性体现在其从逻辑上扩充了内存的容量(可以运行实际内存需求比物理内存大的应用程序)。虚拟性是虚拟存储器的最重要特征也是其最终目标。虚拟性建立在多次性和对换性的基础上行,多次性和对换性又建立在离散分配的基础上。


4. 页面置换算法

在地址映射过程中(虚拟内存机制),若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时,如果操作系统内存中没有空闲页面,则操作系统必须在内存选择一个页面将其移出内存,以便为即将调入的页面让出空间。而用来选择淘汰哪一页的规则叫做页面置换算法。

  1. 最佳置换算法:只具有理论意义的算法,用来评价其他页面置换算法。置换策略是将当前页面中在未来最长时间内不会被访问的页置换出去。

  2. 先进先出FIFO置换算法:简单粗暴的一种置换算法,没有考虑页面访问频率信息。每次淘汰最早调入的页面。该算法存在Belady现象,即可能出现随着分配的物理页面数增加,缺页率反而提高的异常现象。

  3. 最近最久未使用算法LRU:算法赋予每个页面一个访问字段,用来记录上次页面被访问到现在所经历的时间t,每次置换的时候把t值最大的页面置换出去(实现方面可以采用寄存器或者栈的方式实现)。

  4. 时钟算法Clock (最近未使用算法NRU):页面设置一个访问位,并将页面链接为一个环形队列,页面被访问的时候访问位设置为1。页面置换的时候,如果当前指针所指页面访问为0,那么置换,否则将其置为0,循环直到遇到一个访问为位0的页面。

  5. 改进型Clock算法(二次机会法):在Clock算法的基础上添加一个修改位(用来判断当前内存中的数据是否有修改),替换时根据访问位和修改位综合判断。优先替换访问位和修改位都是0的页面,其次是访问位为0修改位为1的页面。

LRU计算缺页:

假如现在有一组进程,虚拟页式存储管理的数据块大小为3(也就是这个页式存储区的大小,能放置3个页面)。
假如进程被调度顺序为3 4 2 1 4 5 3 4 5 1 2。问:在该访问中发生的缺页次数是多少?

  1. 开始时,数据块中为空,因此第一个进程被调度时,未命中缓存,此时发生缺页。然后将进程对应数据放入数据块中;
  2. 第二步调用进程4,此时数据块中也没有进程4数据,因此未命中数据块缓存,也发生缺页;
  3. 同理,发生缺页,但是此时数据块已经存满了数据,下一步如果加入新数据,将会剔除掉数据块尾部的数据;
  4. 插入新进程的数据1,此时将队尾的数据剔除掉。当然这个数据1也未命中,发生缺页;
  5. 调用到数据4,此时数据4在数据块缓存中,所以没有发生缺页。然后将数据4重新插入到数据块的首部。

5. 更多问题

5.1 计算机内存模型

CPU和缓存一致性

随着CPU技术的发展,CPU的执行速度越来越快。而由于内存的技术并没有太大的变化,所以从内存中读取和写入数据的过程和CPU的执行速度比起来差距就会越来越大,这就导致CPU每次操作内存都要耗费很多等待时间。所以,人们想出来了一个好的办法,就是在CPU和内存之间增加高速缓存。缓存的概念大家都知道,就是保存一份数据拷贝。他的特点是速度快,内存小,并且昂贵。

那么,当程序在运行过程中,会将运算需要的数据从主存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主存当中。

而随着CPU能力的不断提升,一层缓存就慢慢的无法满足要求了,就逐渐的衍生出多级缓存。

按照数据读取顺序和与CPU结合的紧密程度,CPU缓存可以分为一级缓存(L1),二级缓存(L2),部分高端CPU还具有三级缓存(L3),每一级缓存中所储存的全部数据都是下一级缓存的一部分。

这三种缓存的技术难度和制造成本是相对递减的,所以其容量也是相对递增的。

当CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找。

单核CPU只含有一套L1,L2,L3缓存;如果CPU含有多个核心,即多核CPU,则每个核心都含有一套L1(甚至和L2)缓存,而共享L3(或者和L2)缓存。

**单线程:**CPU核心的缓存只被一个线程访问。缓存独占,不会出现访问冲突等问题。

**单核CPU,多线程:**进程中的多个线程会同时访问进程中的共享数据,CPU将某块内存加载到缓存后,不同线程在访问相同的物理地址的时候,都会映射到相同的缓存位置,这样即使发生线程的切换,缓存仍然不会失效。但由于任何时刻只能有一个线程在执行,因此不会出现缓存访问冲突。

**多核CPU,多线程:**每个核都至少有一个L1 缓存。多个线程访问进程中的某个共享内存,且这多个线程分别在不同的核心上执行,则每个核心都会在各自的cache中保留一份共享内存的缓冲。由于多核是可以并行的,可能会出现多个线程同时写各自的缓存的情况,而各自的cache之间的数据就有可能不同。

在CPU和主存之间增加缓存,在多线程场景下就可能存在缓存一致性问题,也就是说,在多核CPU中,每个核在自己的缓存中,关于同一个数据的缓存内容可能不一致。


处理器优化和指令重排

在CPU和主存之间增加缓存,在多线程场景下会存在缓存一致性问题。除了这种情况,还有一种硬件问题也比较重要。那就是为了使处理器内部的运算单元能够尽量的被充分利用,处理器可能会对输入代码进行乱序执行处理。这就是处理器优化

除了现在很多流行的处理器会对代码进行优化乱序处理,很多编程语言的编译器也会有类似的优化,比如Java虚拟机的即时编译器(JIT)也会做指令重排

可想而知,如果任由处理器优化和编译器对指令重排的话,就可能导致各种各样的问题。


并发编程的问题

原子性:是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行。

可见性:是指当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值。

有序性:即程序执行的顺序按照代码的先后顺序执行。

缓存一致性问题其实就是可见性问题

处理器优化是可以导致原子性问题;

指令重排会导致有序性问题


5.2 IO中的异步、同步和阻塞、非阻塞

同步和异步最大的区别就是被调用方的执行方式和返回时机。

同步指的是被调用方做完事情之后再返回,异步指的是被调用方先返回,然后再做事情,做完之后再想办法通知调用方。A调用B,B的处理是同步的,在处理完之前他不会通知A,只有处理完之后才会明确的通知A;

异步请求,A调用B,B的处理是异步的,B在接到请求后先告诉A我已经接到请求了,然后异步去处理,处理完之后通过回调等方式再通知A。


阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。

阻塞请求,A调用B,A一直等着B的返回,别的事情什么也不干。

非阻塞请求,A调用B,A不用一直等着B的返回,先去忙别的事情了。

阻塞调用:调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。

非阻塞调用:不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

同步是个过程,阻塞是线程的一种状态。

同步、异步说的是被调用者会不会通知,阻塞、非阻塞说的是调用者会不会卡住不动。


5.3 内核态和用户态

在Linux系统中特权级别分为0,1,2,3一共四个界别,0最大 ,3最小。一般内核代码运行在0特权级,驱动 ,虚拟机等运行在1,2特权级,而我们自己写的程序一般运行在3特权级,也就是最低级别。

当程序运行在3级特权级上时,就可以称之为运行在用户态,因为这是最低特权级,是普通的用户进程运行的特权级,大部分用户直接面对的程序都是运行在用户态;反之,当程序运行在3级特权级下时,就可以称之为运行在内核态。

虽然用户态下和内核态下工作的程序有很多差别,但最重要的差别就在于特权级的不同,即权力的不同。运行在用户态下的程序不能直接访问操作系统内核数据结构和程序。当我们在系统中执行一个程序时,大部分时间是运行在用户态下的,在其需要操作系统帮助完成某些它没有权力和能力完成的工作时就会切换到内核态。

用户态切换到内核态的3种方式

  1. 系统调用:这是用户态进程主动要求切换到内核态的一种方式,用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作。而系统调用的机制其核心还是使用了操作系统为用户特别开放的一个中断来实现,例如Linux的int 80h中断。

  2. 异常:当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。

  3. 外围设备的中断:当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。


5.4 句柄

Windows是一个以虚拟内存为基础的操作系统,很多时候,进程的代码和数据并不全部装入内存,进程的某一段装入内存后,还可能被换出到外存,当再次需要时,再装入内存。两次装入的地址绝大多数情况下是不一样的。也就是说,同一对象在内存中的地址会变化。那么,程序怎么才能准确地访问到对象呢?为了解决这个问题,Windows引入了句柄。

系统为每个进程在内存中分配一定的区域,用来存放各个句柄,即一个个32位无符号整型值(32位操作系统中)。每个32位无符号整型值相当于一个指针,指向内存中的另一个区域(我们不妨称之为区域A)。而区域A中存放的正是对象在内存中的地址。当对象在内存中的位置发生变化时,区域A的值被更新,变为当前时刻对象在内存中的地址,而在这个过程中,区域A的位置以及对应句柄的值是不发生变化的。这种机制,用一种形象的说法可以表述为:有一个固定的地址(句柄),指向一个固定的位置(区域A),而区域A中的值可以动态地变化,它时刻记录着当前时刻对象在内存中的地址。这样,无论对象的位置在内存中如何变化,只要我们掌握了句柄的值,就可以找到区域A,进而找到该对象。而句柄的值在程序本次运行期间是绝对不变的,我们(即系统)当然可以掌握它。

可以这么理解句柄:

  • 数值上,是一个32位无符号整型值(32位系统下);
  • 逻辑上,相当于指针的指针;
  • 形象理解上,是Windows中各个对象的一个唯一的、固定不变的ID;
  • 作用上,Windows使用句柄来标识诸如窗口、位图、画笔等对象,并通过句柄找到这些对象。

细节:

  • 所谓“唯一”、“不变”是指在程序的一次运行中。如果本次运行完,关闭程序,再次启动程序运行,那么这次运行中,同一对象的句柄的值和上次运行时比较,一般是不一样的。

  • 句柄是对象生成时系统指定的,属性是只读的,程序员不能修改句柄。

  • 不同的系统中,句柄的大小(字节数)是不同的,可以使用sizeof()来计算句柄的大小。

  • 通过句柄,程序员只能调用系统提供的服务(即API调用),不能像使用指针那样,做其它的事。


5.5 颠簸

颠簸本质上是指频繁的页调度行为,具体来讲,进程发生缺页中断,这时,必须置换某一页。然而,其他所有的页都在使用,它置换一个页,但又立刻再次需要这个页。因此,会不断产生缺页中断,导致整个系统的效率急剧下降,这种现象称为颠簸(抖动)。

内存颠簸的解决策略包括:

  • 如果是因为页面替换策略失误,可以修改替换算法来解决这个问题;
  • 如果是因为运行的程序太多,造成程序无法同时将所有频繁访问的页面调入内存,则要降低多道程序的数量;
  • 否则,还剩下两个办法:终止该进程或增加物理内存容量。

5.6 总线锁、缓存锁、MESI

处理器需要保证读一个字节或写一个字节是原子的,何实现两种机制:总线锁定和缓存一致性

现在服务器通常是多 CPU,更普遍的是,每块CPU里有多个内核,而每个内核都维护了自己的缓存,那么这时候多线程并发就会存在缓存不一致性,这会导致严重问题。

**操作系统提供了总线锁定的机制。**前端总线(也叫CPU总线)是所有CPU与芯片组连接的主干道,负责CPU与外界所有部件的通信,包括高速缓存、内存、北桥,其控制总线向各个部件发送控制信号、通过地址总线发送地址信号指定其要访问的部件、通过数据总线双向传输。在CPU1要做 如i++操作的时候,其在总线上发出一个LOCK#信号,其他处理器就不能操作缓存了该共享变量内存地址的缓存,也就是阻塞了其他CPU,使该处理器可以独享此共享内存。

但我们只需要对此共享变量的操作是原子就可以了,而总线锁定把CPU和内存的通信给锁住了,使得在锁定期间,其他处理器不能操作其他内存地址的数据,从而开销较大,所以后来的CPU都提供了缓存一致性机制,Intel的奔腾486之后就提供了这种优化。

缓存一致性:缓存一致性机制就整体来说,是当某块CPU对缓存中的数据进行操作了之后,就通知其他CPU放弃储存在它们内部的缓存,或者从主内存中重新读取,用MESI阐述原理如下:

MESI协议:是以缓存行(缓存的基本数据单位,在Intel的CPU上一般是64字节)的几个状态来命名的(全名是Modified、Exclusive、 Share or Invalid)。该协议要求在每个缓存行上维护两个状态位,使得每个数据单位可能处于M、E、S和I这四种状态之一,各种状态含义如下:

  • M:被修改的。处于这一状态的数据,只在本CPU中有缓存数据,而其他CPU中没有。同时其状态相对于内存中的值来说,是已经被修改的,且没有更新到内存中。
  • E:独占的。处于这一状态的数据,只有在本CPU中有缓存,且其数据没有修改,即与内存中一致。
  • S:共享的。处于这一状态的数据在多个CPU中都有缓存,且与内存一致。
  • I:无效的。本CPU中的这份缓存已经无效。

一个处于M状态的缓存行,必须时刻监听所有试图读取该缓存行对应的主存地址的操作,如果监听到,则必须在此操作执行前把其缓存行中的数据写回CPU。
一个处于S状态的缓存行,必须时刻监听使该缓存行无效或者独享该缓存行的请求,如果监听到,则必须把其缓存行状态设置为I。
一个处于E状态的缓存行,必须时刻监听其他试图读取该缓存行对应的主存地址的操作,如果监听到,则必须把其缓存行状态设置为S。

当CPU需要读取数据时,如果其缓存行的状态是I的,则需要从内存中读取,并把自己状态变成S,如果不是I,则可以直接读取缓存中的值,但在此之前,必须要等待其他CPU的监听结果,如其他CPU也有该数据的缓存且状态是M,则需要等待其把缓存更新到内存之后,再读取。

当CPU需要写数据时,只有在其缓存行是M或者E的时候才能执行,否则需要发出特殊的RFO指令(Read Or Ownership,这是一种总线事务),通知其他CPU置缓存无效(I),这种情况下性能开销是相对较大的。在写入完成后,修改其缓存状态为M。

所以如果一个变量在某段时间只被一个线程频繁地修改,则使用其内部缓存就完全可以办到,不涉及到总线事务,如果缓存一会被这个CPU独占、一会被那个CPU 独占,这时才会不断产生RFO指令影响到并发性能。这里说的缓存频繁被独占并不是指线程越多越容易触发,而是这里的CPU协调机制,这有点类似于有时多线程并不一定提高效率,原因是线程挂起、调度的开销比执行任务的开销还要大,这里的多CPU也是一样,如果在CPU间调度不合理,也会形成RFO指令的开销比任务开销还要大。当然,这不是编程者需要考虑的事,操作系统会有相应的内存地址的相关判断。

并非所有情况都会使用缓存一致性的,如被操作的数据不能被缓存在CPU内部或操作数据跨越多个缓存行(状态无法标识),则处理器会调用总线锁定;另外当CPU不支持缓存锁定时,自然也只能用总线锁定了,比如说奔腾486以及更老的CPU。


5.7 缓冲区溢出

https://blog.csdn.net/qq_35642036/article/details/82809845

所谓缓冲区可以更抽象地理解为一段可读写的内存区域,缓冲区攻击的最终目的就是希望系统能执行这块可读写内存中已经被蓄意设定好的恶意代码。按照冯·诺依曼存储程序原理,程序代码是作为二进制数据存储在内存的,同样程序的数据也在内存中,因此直接从内存的二进制形式上是无法区分哪些是数据哪些是代码的,这也为缓冲区溢出攻击提供了可能。

缓冲区溢出是指当计算机向缓冲区填充数据时超出了缓冲区本身的容量,溢出的数据覆盖在合法数据上。

危害:

  1. 程序崩溃,导致拒绝服务;
  2. 跳转并且执行一段恶意代码。

原因:主要原因是程序中没有仔细检查用户输入。

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. Python基础知识学习12:面向对象的三大特征及多态的介绍

    1、面向对象三大特征 封装 将属性和方法书写到类的里面的操作即为封装 封装可以为属性和方法添加私有权限 继承 子类默认继承父类的所有属性和方法 子类可以重写父类属性和方法 多态 传入不同的对象&#xff0c;产生不不同的结果 2、多态 多态指的是一类事物有多种形态&…...

    2024/5/9 19:25:37
  2. python selenium破解极验3滑动验证码

    python selenium破解极验3滑动验证码&#xff0c;解决物理公式不可用的问题 一、采用物理加速度公式算法 def get_track(self, distance):"""获取滑块移动轨迹的列表:param distance: 第二个缺块的左侧的x坐标:return: 滑块移动轨迹列表"""tra…...

    2024/4/6 7:00:44
  3. 从初级工程师发展到高级工程师,需要跨越的鸿沟

    转载地址&#xff1a;https://www.toutiao.com/a6878215946150871559/ 程序员是吃青春饭的吗&#xff1f;等我们老了&#xff0c;技术过时了&#xff0c;公司有什么理由不裁掉我们&#xff0c;去雇一些既有活力、薪资要求又低的年轻人呢&#xff1f;这个老生常谈的问题困扰着诸…...

    2024/5/10 14:41:34
  4. python基础(1)中文文本分析

    中文文本分析相关库 中文分词jiaba库 函数描述jiba.cut(s)精确模式&#xff0c;返回一个可迭代数据类型jieba.cut(s,cut_allTrue)全模式&#xff0c;输出文本s中所有可能单词jiba.cut_for_search(s)搜索引擎模式&#xff0c;适合搜索引擎建立索引的分词结果jiaba.lcut(s)精确…...

    2024/5/10 12:56:54
  5. 监听器的巧妙使用

    监听器的巧妙使用 1、场景&#xff1a; &#xff08;1&#xff09;通过弹窗实现类的构造方法&#xff0c;生成类对象&#xff0c;在构造方法中有initView()方法&#xff0c;在initView()方法中&#xff0c;会实现会弹窗布局的inflate() &#xff08;2&#xff09;调用类对象的…...

    2024/4/25 2:37:50
  6. Java数组的定义和使用(一)

    一、数组基本用法 1.1 什么是数组 数组本质上就是让我们能 “批量” 创建相同类型的变量. 例如&#xff1a; 如果需要表示两个数据&#xff0c;那么直接定义两个变量即可 int a&#xff1b;int b 如果需要表示五个数据&#xff0c;那么也可以照上面的方法定义五个变量。 那么问…...

    2024/4/23 6:30:25
  7. 浅谈Java数组(一)

    一、数组基本用法 1.1 什么是数组 数组本质上就是让我们能 “批量” 创建相同类型的变量. 例如&#xff1a; 如果需要表示两个数据&#xff0c;那么直接定义两个变量即可 int a&#xff1b;int b 如果需要表示五个数据&#xff0c;那么也可以照上面的方法定义五个变量。 那么问…...

    2024/4/24 5:24:02
  8. vue-cli脚手架搭建项目

    1.npm i -g vue/cli 2. vue --version 3. vue create 项目名称 或者vue ui(界面性创建项目) 第一次配置 注意&#xff1a; 如果想删除默认的配置&#xff1a; 找到 C:\Users\用户名\.vuerc 文件&#xff0c;进行修改即可。 第一次配置的时候就按照上面去操作 以后可以用默…...

    2024/4/6 8:16:07
  9. Vue学习(十一)——作用域

    1.组件的作用域 我们在定义组件时&#xff0c;作用域是组件本身&#xff0c;在调用组件时&#xff0c;作用域是父组件 2.作用域插槽 由于我们子组件中的数据不能再父组件中使用&#xff0c;所以我们在需要为slot传入标签时使用子组件数据的时候为slot动态绑定一个属性名xxx&…...

    2024/4/26 0:27:04
  10. 接口文档下的渗透测试

    接口文档背景 随着前后端分离架构的优势越来越明显&#xff0c;前后端分离的应用场景也越来越广&#xff0c;如今前后端分离已成为互联网项目开发的业界标准使用方式&#xff0c;而为了前后端程序员在实际开发中能够有统一的接口文档去调试&#xff0c;因此也随着衍生出了很多…...

    2024/4/30 22:25:49
  11. [NOIP2012]开车旅行

    题意简述 有n个城市&#xff0c;海拔高度互不相同。小A和小B驾驶一辆车游览这些城市&#xff0c;他们从某一个城市S出发&#xff0c;两人轮流开车&#xff08;小A先开&#xff0c;小B后开&#xff09;&#xff0c;一直向东前进&#xff08;编号大的城市在东边&#xff09;。 …...

    2024/4/15 17:24:58
  12. 数据库链接时的时区问题serverTimezone永久解决

    错误原因: 时区错误&#xff0c;MySQL默认的时区是UTC时区&#xff0c;比北京时间晚8个小时。所以要修改mysql的时区。 解决方法&#xff1a; 1.找到mysql安装目录下的my.ini文件&#xff08;我的是在C盘&#xff0c;建议直接使用检索工具&#xff09; 2.在[mysqId]下添加语句&…...

    2024/5/2 19:50:21
  13. Java数组的定义和使用

    一、数组基本用法 1.1 什么是数组 数组本质上就是让我们能 “批量” 创建相同类型的变量. 例如&#xff1a; 如果需要表示两个数据&#xff0c;那么直接定义两个变量即可 int a&#xff1b;int b 如果需要表示五个数据&#xff0c;那么也可以照上面的方法定义五个变量。 那么问…...

    2024/5/2 10:20:55
  14. 每日算法----最后一个单词的长度----2020/10/15

    目录1. 题目描述2. 示例3. 思路4. 遇上的问题5. 具体实现代码6. 学习收获,优秀题解一如既往的妙啊7 题目来源1. 题目描述 给定一个仅包含大小写字母和空格 ’ ’ 的字符串 s&#xff0c;返回其最后一个单词的长度。如果字符串从左向右滚动显示&#xff0c;那么最后一个单词就是…...

    2024/5/7 13:10:33
  15. 2020.10.14 第16节课 文件操作

    2020.10.14 第16节课 文件操作 一、文件操作基础 基本流程 读写方式 类型 文件指针表示一个文件 **stdin: 标准输入 ---->键盘输入 fflush(stdin); ****stdout: 标准输出---->控台的窗口 自定义类型文件: 文件指针 *FILE fp; 1.打开文件 1.1 路径 1.2 读写方式 防…...

    2024/4/24 15:24:28
  16. 149【毕设课设】基于51单片机的智能疏散系统-烟雾检测蓝牙报警(电路图+程序+论文)

    【资源下载】下载地址如下&#xff1a;https://docs.qq.com/doc/DTlRSd01BZXNpRUxl 基于51单片机的智能疏散系统烟雾检测蓝牙报警器设计-&#xff08;电路图程序源码论文&#xff09; 本系统由STC89C52单片机核心电路烟雾传感器检测电路蜂鸣器报警电路语音播放电路1路红色指示…...

    2024/4/6 8:15:59
  17. 为什么 我的data 中的值我刚开始一直引用不到,原来是我犯了这样一个错误

    我犯了一个这样的错误 data 中的数据引用错误&#xff0c; 误以为使用this.数据直接能后能取到&#xff0c;实际上是必须 this.data.数据 才能拿到 2. 使用错误的测试结果&#xff1a;...

    2024/5/2 12:41:47
  18. 数据库练习题8--用户管理习题

    实验目的 掌握用户的管理、数据库的备份与恢复&#xff1b; 用户管理&#xff1a; 请使用T-SQL 语句实现进行以下操作&#xff1a; 1.创建SQL Server身份验证的登录账户。登录名为&#xff1a;SQL_User1&#xff0c;密码为&#xff1a;123456 create login SQL_User1 with pas…...

    2024/5/10 14:51:10
  19. 面试集锦(四)多线程

    4. 多线程 https://blog.csdn.net/justloveyou_/article/details/78313167 https://www.cnblogs.com/Qian123/p/5683554.html 4.1 概念 Java给多线程编程提供了内置的支持。一个多线程程序包含两个或多个能并发运行的部分。程序的每一部分都称作一个线程&#xff0c;并且每…...

    2024/4/26 9:56:40
  20. Yocto实践(1): 基于Dunfell 构建Yocto项目

    因为工作中很多时候需要基于Yocto来改代码、编译SDK&#xff0c;很久之前就想彻底搞明白Yocto的理念、整个构建的细节。 现在开坑&#xff0c;基于Yocto官方文档&#xff0c;以实践记录网络资料整理的方式&#xff0c;希望加深对Yocto的理解。 操作基于2020年4月份发行的3.1版…...

    2024/4/26 0:14:17

最新文章

  1. pytorch中统计一个数在tensor中出现了几次

    pytorch中统计一个数在tensor中出现了几次 在PyTorch中&#xff0c;可以使用torch.eq()函数配合torch.sum()来统计某个数值在Tensor中出现的次数。torch.eq()函数会返回一个新的Tensor&#xff0c;其中对于每个元素来说&#xff0c;如果和指定的数值相等&#xff0c;则该位置为…...

    2024/5/10 18:03:29
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/5/9 21:23:04
  3. uniapp原生下拉刷新在手机上不起作用

    开启原生下拉刷新时&#xff0c;页面里使用了全屏高的scroll-view&#xff0c;向下拖动内容时&#xff0c;会优先触发scroll-view滚动而不是下拉刷新。 "enablePullDownRefresh": true, 这就可能会导致下拉刷新不起作用&#xff0c;这时候就需要做到取舍&#xff0c…...

    2024/5/10 14:45:20
  4. WKWebView的使用

    一、简介 在iOS中&#xff0c;WKWebView是WebKit框架提供的一个用于展示网页内容的控件&#xff0c;相比UIWebView有更好的性能和功能。 以下是在iOS中使用WKWebView的基本步骤&#xff1a; 1.1 导入WebKit框架 import WebKit1.2 创建WKWebView实例 let webView WKWebVie…...

    2024/5/10 0:18:27
  5. 理解 Golang 变量在内存分配中的规则

    为什么有些变量在堆中分配、有些却在栈中分配&#xff1f; 我们先看来栈和堆的特点&#xff1a; 简单总结就是&#xff1a; 栈&#xff1a;函数局部变量&#xff0c;小数据 堆&#xff1a;大的局部变量&#xff0c;函数内部产生逃逸的变量&#xff0c;动态分配的数据&#x…...

    2024/5/10 0:16:17
  6. 416. 分割等和子集问题(动态规划)

    题目 题解 class Solution:def canPartition(self, nums: List[int]) -> bool:# badcaseif not nums:return True# 不能被2整除if sum(nums) % 2 ! 0:return False# 状态定义&#xff1a;dp[i][j]表示当背包容量为j&#xff0c;用前i个物品是否正好可以将背包填满&#xff…...

    2024/5/10 1:36:26
  7. 【Java】ExcelWriter自适应宽度工具类(支持中文)

    工具类 import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;/*** Excel工具类** author xiaoming* date 2023/11/17 10:40*/ public class ExcelUti…...

    2024/5/10 16:45:57
  8. Spring cloud负载均衡@LoadBalanced LoadBalancerClient

    LoadBalance vs Ribbon 由于Spring cloud2020之后移除了Ribbon&#xff0c;直接使用Spring Cloud LoadBalancer作为客户端负载均衡组件&#xff0c;我们讨论Spring负载均衡以Spring Cloud2020之后版本为主&#xff0c;学习Spring Cloud LoadBalance&#xff0c;暂不讨论Ribbon…...

    2024/5/10 16:45:56
  9. TSINGSEE青犀AI智能分析+视频监控工业园区周界安全防范方案

    一、背景需求分析 在工业产业园、化工园或生产制造园区中&#xff0c;周界防范意义重大&#xff0c;对园区的安全起到重要的作用。常规的安防方式是采用人员巡查&#xff0c;人力投入成本大而且效率低。周界一旦被破坏或入侵&#xff0c;会影响园区人员和资产安全&#xff0c;…...

    2024/5/10 2:07:45
  10. VB.net WebBrowser网页元素抓取分析方法

    在用WebBrowser编程实现网页操作自动化时&#xff0c;常要分析网页Html&#xff0c;例如网页在加载数据时&#xff0c;常会显示“系统处理中&#xff0c;请稍候..”&#xff0c;我们需要在数据加载完成后才能继续下一步操作&#xff0c;如何抓取这个信息的网页html元素变化&…...

    2024/5/10 8:07:24
  11. 【Objective-C】Objective-C汇总

    方法定义 参考&#xff1a;https://www.yiibai.com/objective_c/objective_c_functions.html Objective-C编程语言中方法定义的一般形式如下 - (return_type) method_name:( argumentType1 )argumentName1 joiningArgument2:( argumentType2 )argumentName2 ... joiningArgu…...

    2024/5/10 16:45:52
  12. 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】

    &#x1f468;‍&#x1f4bb;博客主页&#xff1a;花无缺 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 花无缺 原创 收录于专栏 【洛谷算法题】 文章目录 【洛谷算法题】P5713-洛谷团队系统【入门2分支结构】&#x1f30f;题目描述&#x1f30f;输入格…...

    2024/5/10 8:16:30
  13. 【ES6.0】- 扩展运算符(...)

    【ES6.0】- 扩展运算符... 文章目录 【ES6.0】- 扩展运算符...一、概述二、拷贝数组对象三、合并操作四、参数传递五、数组去重六、字符串转字符数组七、NodeList转数组八、解构变量九、打印日志十、总结 一、概述 **扩展运算符(...)**允许一个表达式在期望多个参数&#xff0…...

    2024/5/10 2:07:43
  14. 摩根看好的前智能硬件头部品牌双11交易数据极度异常!——是模式创新还是饮鸩止渴?

    文 | 螳螂观察 作者 | 李燃 双11狂欢已落下帷幕&#xff0c;各大品牌纷纷晒出优异的成绩单&#xff0c;摩根士丹利投资的智能硬件头部品牌凯迪仕也不例外。然而有爆料称&#xff0c;在自媒体平台发布霸榜各大榜单喜讯的凯迪仕智能锁&#xff0c;多个平台数据都表现出极度异常…...

    2024/5/10 2:07:43
  15. Go语言常用命令详解(二)

    文章目录 前言常用命令go bug示例参数说明 go doc示例参数说明 go env示例 go fix示例 go fmt示例 go generate示例 总结写在最后 前言 接着上一篇继续介绍Go语言的常用命令 常用命令 以下是一些常用的Go命令&#xff0c;这些命令可以帮助您在Go开发中进行编译、测试、运行和…...

    2024/5/10 16:45:47
  16. 用欧拉路径判断图同构推出reverse合法性:1116T4

    http://cplusoj.com/d/senior/p/SS231116D 假设我们要把 a a a 变成 b b b&#xff0c;我们在 a i a_i ai​ 和 a i 1 a_{i1} ai1​ 之间连边&#xff0c; b b b 同理&#xff0c;则 a a a 能变成 b b b 的充要条件是两图 A , B A,B A,B 同构。 必要性显然&#xff0…...

    2024/5/10 16:45:46
  17. 【NGINX--1】基础知识

    1、在 Debian/Ubuntu 上安装 NGINX 在 Debian 或 Ubuntu 机器上安装 NGINX 开源版。 更新已配置源的软件包信息&#xff0c;并安装一些有助于配置官方 NGINX 软件包仓库的软件包&#xff1a; apt-get update apt install -y curl gnupg2 ca-certificates lsb-release debian-…...

    2024/5/9 19:47:07
  18. Hive默认分割符、存储格式与数据压缩

    目录 1、Hive默认分割符2、Hive存储格式3、Hive数据压缩 1、Hive默认分割符 Hive创建表时指定的行受限&#xff08;ROW FORMAT&#xff09;配置标准HQL为&#xff1a; ... ROW FORMAT DELIMITED FIELDS TERMINATED BY \u0001 COLLECTION ITEMS TERMINATED BY , MAP KEYS TERMI…...

    2024/5/10 10:17:11
  19. 【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

    文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…...

    2024/5/10 2:07:41
  20. --max-old-space-size=8192报错

    vue项目运行时&#xff0c;如果经常运行慢&#xff0c;崩溃停止服务&#xff0c;报如下错误 FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory 因为在 Node 中&#xff0c;通过JavaScript使用内存时只能使用部分内存&#xff08;64位系统&…...

    2024/5/10 16:37:19
  21. 基于深度学习的恶意软件检测

    恶意软件是指恶意软件犯罪者用来感染个人计算机或整个组织的网络的软件。 它利用目标系统漏洞&#xff0c;例如可以被劫持的合法软件&#xff08;例如浏览器或 Web 应用程序插件&#xff09;中的错误。 恶意软件渗透可能会造成灾难性的后果&#xff0c;包括数据被盗、勒索或网…...

    2024/5/10 15:01:36
  22. JS原型对象prototype

    让我简单的为大家介绍一下原型对象prototype吧&#xff01; 使用原型实现方法共享 1.构造函数通过原型分配的函数是所有对象所 共享的。 2.JavaScript 规定&#xff0c;每一个构造函数都有一个 prototype 属性&#xff0c;指向另一个对象&#xff0c;所以我们也称为原型对象…...

    2024/5/9 16:54:42
  23. C++中只能有一个实例的单例类

    C中只能有一个实例的单例类 前面讨论的 President 类很不错&#xff0c;但存在一个缺陷&#xff1a;无法禁止通过实例化多个对象来创建多名总统&#xff1a; President One, Two, Three; 由于复制构造函数是私有的&#xff0c;其中每个对象都是不可复制的&#xff0c;但您的目…...

    2024/5/10 1:31:37
  24. python django 小程序图书借阅源码

    开发工具&#xff1a; PyCharm&#xff0c;mysql5.7&#xff0c;微信开发者工具 技术说明&#xff1a; python django html 小程序 功能介绍&#xff1a; 用户端&#xff1a; 登录注册&#xff08;含授权登录&#xff09; 首页显示搜索图书&#xff0c;轮播图&#xff0…...

    2024/5/10 9:24:29
  25. 电子学会C/C++编程等级考试2022年03月(一级)真题解析

    C/C++等级考试(1~8级)全部真题・点这里 第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536输入 只有一行,一个双精度浮点数。输出 一行,保留8位小数的浮点数。样例输入 3.1415926535798932样例输出 3.1…...

    2024/5/10 10:40:03
  26. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  27. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  28. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  29. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  30. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  31. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  32. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  33. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  34. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  35. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  36. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  37. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  38. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  39. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  40. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  41. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  42. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  43. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  44. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  45. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57