目录

校园招聘面试-操作系统知识总结

目录

校园招聘面试-操作系统知识总结

有问题请扫描下图

https://img-blog.csdn.net/20160711194736899?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

进程的有哪几种状态,状态转换图,及导致转换的事件 。

状态:

1 )就

绪状态  进程已获得除处理机外的所需资源,等待分配处理机资源,只要分配到 CPU

就可执行。在某一时刻,可能有若干个进程处于该状态。

2 )运行状态

占用处理机资源运行,处于此状态的进程的数目小于等于 CPU

的数目。

3 )阻塞状态  由于进程等待某种条件(如

I/O

操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理机分配给该进程,也无法运行。

转换解释:从状态转换图中,存在四种状态转换。

当进程调度程序从就绪队列中选取一个进程投入运行时引起转换 1

正在执行的进程如因时间片用完而被暂停执行就会引起转换 2

正在执行的进程因等待的事件尚未发生而无法执行(如进程请求完成 I/O

)会引去转换

3

当进程等待的事件发生时(如 I/O

完成)则会引起转换

4

事件:就绪队列非空,则一个进程的转换 3

会立即引去另一个进程的转换

1

。这是因为一个进程发生转换

3

意味着正在执行的进程由执行状态变为阻塞状态,这时处理机空闲,进程调度程序必然会从就绪队列中选取一个进程并将它投入运行,因此只要就绪队列非空,一个进程的转换

3

能立即引起一个进程的转换

1

进程与线程的区别。

dll 是否有独立的堆栈

?

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动 ,

进程是系统进行资源分配和调度的一个独立单位

.

线程是进程的一个实体 ,

CPU

调度和分派的基本单位

,

它是比进程更小的能独立运行的基本单位

.

线程自己基本上不拥有系统资源

,

只拥有一点在运行中必不可少的资源

(

如程序计数器

,

一组寄存器和栈

),

但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源

.

一个线程可以创建和撤销另一个线程 ;

同一个进程中的多个线程之间可以并发执行

进程是死的,只是一些资源的集合,真正的程序执行都是线程来完成的,程序启动的时候操作系统就帮你创建了一个主线程。每个线程有自己的堆栈。 DLL

(动态连接库)中有没有独立的堆栈,这个问题不好回答,或者说这个问题本身是否有问题。因为

DLL

中的代码是被某些线程所执行,只有线程拥有堆栈,如果

DLL

中的代码是

EXE

中的线程所调用,那么这个时候是不是说这个

DLL

没有自己独立的堆栈?如果

DLL

中的代码是由

DLL

自己创建的线程所执行,那么是不是说

DLL

有独立的堆栈?以上讲的是堆栈,如果对于堆来说,每个

DLL

有自己的堆,所以如果是从

DLL

中动态分配的内存,最好是从

DLL

中删除,如果你从

DLL

中分配内存,然后在

EXE

中,或者另外一个

DLL

中删除,很有可能导致程序崩溃。

另进程和程序的区别:

进程即运行中的程序,从中即可知,进程是在运行的,程序是非运行的,当然本质区别就是动态和静态的区别。程序可以存在外存中,也可以存在内存中

进程通信的几种方式。

管道 ( pipe )

: 管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

有名管道 (named pipe)

: 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

信号量 ( semophore )

: 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

消息队列 ( message queue )

: 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

信号 ( signal )

: 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

共享内存 ( shared memory )

: 共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC

方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

套接字 ( socket )

: 套解字也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

线程同步几种方式 。 (

一定要会写生产者、消费者问题,完全消化理解

)

临界区( CCriticalSection

):通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。

事件( CEvent

):

为协调共同对一个共享资源的单独访问而设计的。

互斥量( CMutex

):

为控制一个具有有限数量用户资源而设计。

信号量( CSemaphore

):

用来通知线程有一些事件已发生,从而启动后继任务的开始。

生产者、消费者问题

Var mutex,empty,full:semaphore:=1,n,0;  // 定义三个信号量

buffer:array[0,…,n-1]of item;  // 定义缓冲池,容量为

n

in,out:integer:=0,0;

begin

parbegin

proceducer:begin // 生产者

repeat

producer an item nextp; // 生产一个产品

.

wait(empty);   // 申请一个空缓冲区

wait(mutex);  // 申请缓冲池的使用权

buffer(in):=nextp; // 将产品放入缓冲池中

in:=(in+1)mod n;  // 下一个空缓冲区地址

signal(mutex);  // 释放缓冲池使用权

signal(full);  // 释放一个满缓冲区

until false;

end

consumer:begin

repeat

wait(full);

wait(mutex);

nextc:=buffer(out);

out:=(out+1)mod n;

signal(mutex);

signal(empty);

consumer the item in nextc;

until false;

end

parend

end

nextp 应该是

next proceducer

的意思吧

nextc 应该是

next consumer

貌似也不是什么变量,属于语言描述而已

下面的消费者也是差不多的。

至于生产者进程如何被阻塞和唤醒,因为程序中有一个 repeat

语句,所以进程不断测试缓冲池是否有空缓冲区,以及缓冲池是否有其他进程使用。若两个条件不满足,则进入阻塞队列等待。若某一时刻两个条件都能满足,则能唤醒该进程。

信号量:

只支持两种操作 ,wait()

signal()

,也叫做

P

V

操作,这两个操作是

原子操作,不会被打断。信号量机制有以下几种:

整型信号量


一个整数,只能由

PV

操作对其加减

记录型信号量


1

的基础上种了一个链表,记录请求该资源的线程,解决

1

中没有让权等待的问题

3.AND 信号量

———————1

2

只是对一个资源,而这个机制能解决一次请求多个资源的情况

一般信号量


这是最一般的信号量机制,能够表示以上几种,表示方法也比较特殊,见操作系统

3 和

4

又属于信号量集机制。

线程的实现方式 . (

也就是用户线程与内核线程的区别

)

用户线程与内核线程的区别

根据操作系统内核是否对线程可感知,可以把线程分为内核线程和用户线程。

内核线程建立和销毁都是由操作系统负责、通过系统调用完成的,操作系统在调度时,参考各进程内的线程运行情况做出调度决定,如果一个进程中没有就绪态的线程,那么这个进程也不会被调度占用 CPU

和内核线程相对应的是用户线程,用户线程指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,用户进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。用户线程多见于一些历史悠久的操作系统,例如 Unix

操作系统,不需要用户态

/

核心态切换,速度快,操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少为了在操作系统中加入线程支持,采用了在用户空间增加运行库来实现线程,这些运行库被称为“线程包”,用户线程是不能被操作系统所感知的。

引入用户线程,具体而言,有以下四个方面的优势:

( 1

)可以在不支持线程的操作系统中实现。

( 2

)创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。

( 3

)允许每个进程定制自己的调度算法,线程管理比较灵活。

( 4

)线程能够利用的表空间和堆栈空间比内核级线程多。

用户线程的缺点主要有以下两点:

( 1

)同一进程中只能同时有一个线程在运行,如果有一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。

( 2

)页面失效也会产生类似的问题。

内核线程的优缺点刚好跟用户线程相反。实际上,操作系统可以使用混合的方式来实现线程。

Java 实现线程的方式有三种:

(1) 继承 Thread

类,重写

run

函数

创建:

class xx extends Thread{

public void run(){

Thread.sleep(1000) // 线程休眠

1000

毫秒,

sleep

使线程进入

Block

状态,并释放资源

}}

开启线程:

对象 .start() // 启动线程,

run

函数运行

public class java_thread extends Thread{

public static void main(String args[])

{

(new java_thread()).run();

System.out.println(“main thread run “);

}

public synchronized  void run()

{

System.out.println(“sub thread run “);

}

}

(2) 实现 Runnable

接口,重写

run

函数

开启线程:

Thread t = new Thread( 对象

) // 创建线程对象

t.start()

public class java_thread implements Runnable{

public static void main(String args[])

{

(new Thread(new java_thread())).start();

System.out.println(“main thread run “);

}

public void run()

{

System.out.println(“sub thread run “);

}

}

(3) 实现 Callable

接口,重写

call

函数

Callable 是类似于

Runnable

的接口,实现

Callable

接口的类和实现

Runnable

的类都是可被其它线程执行的任务。

import java.util.concurrent.Callable;

public class CallableWorker implements Callable{

private int i;

public CallableWorker(int i) throws Exception {

this.i = i;}

@Override

public Integer call() throws Exception {

System.out.println(“Thread-” + Thread.currentThread().getId() + " CallableWorker test count " + i + “begin…”);

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“Thread-” + Thread.currentThread().getId() + " CallableWorker test count " + i + “end”);

return i+1;

}}

Callable 和

Runnable

有几点不同

:

① Callable

规定的方法是

call()

,而

Runnable

规定的方法是

run().

② Callable

的任务执行后可返回值,而

Runnable

的任务是不能返回值的

③ call()

方法可抛出异常,而

run()

方法是不能抛出异常的。

④运行 Callable

任务可拿到一个

Future

对象,

Future

表示异步计算的结果。它提供了检查计算是否完成的方法

,

以等待计算的完成

,

并检索计算的结果

.

通过

Future

对象可了解任务执行情况

,

可取消任务的执行

,

还可获取任务执行的结果

用户态和核心态的区别。

当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态)。此时处理器处于特权级最高的( 0

级)内核代码中执行。当进程处于内核态时,执行的内核代码会使用当前进程的内核栈。每个进程都有自己的内核栈。当进程在执行用户自己的代码时,则称其处于用户运行态(用户态)。即此时处理器在特权级最低的(

3

级)用户代码中运行。当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态。因为中断处理程序将使用当前进程的内核栈。这与处于内核态的进程的状态有些类似。

用户态切换到内核态的 3

种方式

:系统调用、异常、外围设备中断。

用户栈和内核栈的区别。

内核栈和用户栈区别:

intel 的

cpu

分为四个运行级别

ring0~ring3

,内核创建进程,创建进程的同时创建进程控制块,创建进程自己的堆栈。一个进程有两个堆栈,用户栈和系统栈。用户堆栈的空间指向用户地址空间,内核堆栈的空间指向内核地址空间。

有个 CPU

堆栈指针寄存器,进程运行的状态有用户态和内核态,当进程运行在用户态时。

CPU

堆栈指针寄存器指向的是用户堆栈地址,使用的是用户堆栈;当进程运行在内核态时,

CPU

堆栈指针寄存器指向的是内核堆栈地址,使用的是内核堆栈。

堆栈切换

当系统因为系统调用(软中断)或硬件中断, CPU

切换到特权工作模式,进程陷入内核态,进程使用的栈也要从用户栈转向系统栈。

从用户态到内核态要两步骤,首先是将用户堆栈地址保存到内核堆栈中,然后将 CPU

堆栈指针寄存器指向内核堆栈。

当由内核态转向用户态,步骤首先是将内核堆栈中得用户堆栈地址恢复到 CPU

堆栈指针寄存器中。

内核栈和用户栈区别

栈是系统运行在内核态的时候使用的栈,用户栈是系统运行在用户态时候使用的栈。

当进程由于中断进入内核态时,系统会把一些用户态的数据信息保存到内核栈中,当返回到用户态时,取出内核栈中得信息恢复出来,返回到程序原来执行的地方。用户栈就是进程在用户空间时创建的栈,比如一般的函数调用,将会用到用户栈。

内核栈是属于操作系统空间的一块固定区域,可以用于保存中断现场、保存操作系统子程序间相互调用的参数、返回值等。用户栈是属于用户进程空间的一块区域,用户保存用户进程子程序间的相互调用的参数、返回值等。

每个

Windows

都有

4g

的进程空间,系统栈使用进程空间的地段部分,用户栈是高端部分如果用户要直接访问系统栈部分,需要有特殊的方式。

为何要设置两个不同的栈 ?

共享原因:内核的代码和数据是为所有的进程共享的,如果不为每一个进程设置对应的内核栈,那么就不能实现不同的进程执行不同的代码。

安全原因:如果只有一个栈,那么用户就可以修改栈内容来突破内核安全保护。

内存池、

进程池、线程池 。 (c++

程序员必须掌握

)

自定义内存池的思想通过这个 "

"

字表露无疑,应用程序可以通过系统的内存分配调用预先一次性申请适当大小的内存作为一个内存池,之后应用程序自己对内存的分配和释放则可以通过这个内存池来完成。只有当内存池大小需要动态扩展时,才需要再调用系统的内存分配函数,其他时间对内存的一切操作都在应用程序的掌控之中。

应用程序自定义的内存池根据不同的适用场景又有不同的类型。

从线程安全的角度来分,内存池可以分为单线程内存池和多线程内存池。单线程内存池整个生命周期只被一个线程使用,因而不需要考虑互斥访问的问题;多线程内存池有可能被多个线程共享,因此则需要在每次分配和释放内存时加锁。相对而言,单线程内存池性能更高,而多线程内存池适用范围更广。

从内存池可分配内存单元大小来分,可以分为固定内存池和可变内存池。所谓固定内存池是指应用程序每次从内存池中分配出来的内存单元大小事先已经确定,是固定不变的;而可变内存池则每次分配的内存单元大小可以按需变化,应用范围更广,而性能比固定内存池要低。

死锁的概念,导致死锁的原因

.

死锁 :

是指两个或两个以上的进程在执行过程中

,

因争夺资源而造成的一种互相等待的现象

,

若无外力作用

,

它们都将无法推进下去

.

此时称系统处于死锁状态或系统产生了死锁

,

这些永远在互相等待的进程称为死锁进程

.

主要原因( 1

) 因为系统资源不足。(

2

) 进程运行推进的顺序不合适。(

3

) 资源分配不当等。

导致死锁的四个必要条件。

产生死锁的四个必要条件:

( 1

) 互斥条件:一个资源每次只能被一个进程使用。

( 2

) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

( 3

) 不剥夺条件

:

进程已获得的资源,在末使用完之前,不能强行剥夺。

( 4

) 循环等待条件

:

若干进程之间形成一种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

处理死锁的四个方式。

1 )忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,

(鸵鸟策略)

2 )检测死锁并且恢复。

(检测与解除策略)

3 )仔细地对资源进行动态分配,以避免死锁。

(避免策略)

4 )通过破除死锁四个必要条件之一,来防止死锁产生。

(预防策略)

预防死锁的方法、避免死锁的方法。

通过破除死锁四个必要条件之一,来预防死锁产生,有两种方法,一种是当其申请的资源得不到满足时,也必须放弃其原先占有的资源;另一种方法是只适用于申请资源的进程优先级比占有该资源的进程优先级高时,如果一个进程申请的资源被其它进程占用,而申请进程的优先级较高,那么它可以强迫占有资源的进程放弃。

仔细地对资源进行动态分配,以避免死锁。

进程调度算法。

(

周转时间

=

程序结束时间

开始服务时间、带权周转时间

=

周转时间

/

要求服务时间

)

先来先服务 (First Come First Service

FCFS) 调度算法按照进程进入就绪队列的先后顺序选择可以占用处理器的进程。这是一种不可抢占方式的调度算法,优点是实现简单,缺点是后来的进程等待 CPU

的时间较长。它现今主要用作辅助调度法;例如结合在优先级调度算法中使用,当有两个最高优先级的进程时,则谁先来,谁就先被调度。

短执行进程优先算法 (Shortest Process First

, SPF) 就是从就绪队列中选择一个

CPU

执行时间预期最短的进程,将处理器分配给它。虽然较公平,但实现难度较大,因为要准确预定下一个进程的

CPU

执行周期是很困难的。

• 最高优先级优先 (Highest Priority First

HPF)

调度算法 的核心是确定进程的优先级。首先,系统或用户按某种原则为进程指定一个优先级来表示该进程所享有的调度优先权。确定优先级的方法较多,一般可分为两类,即静态法和动态法。静态法根据进程的静态特性,在进程开始执行之前就确定它们的优先级,一旦开始执行之后就不能改变。动态法则不然,它把进程的静态特性和动态特性结合起来确定进程的优先级,随着进程的执行过程,其优先级不断变化。

•进程的静态优先级确定最基本的方法是按照进程的类型给予不同的优先级。例如,在有些系统中,进程被划分为系统进程和用户进程。系统进程享有比用户进程高的优先级;对于用户进程来说,则可以分为: I/O

繁忙的进程、

CPU

繁忙的进程、

I/O

CPU

均衡的进程和其他进程等。

•对系统进程,也可以根据其所要完成的功能划分为不同的类型。例如,调度进程、 I/O

进程、中断处理进程、存储管理进程等。这些进程还可进一步划分为不同类型并赋予不同的优先级。例如,在操作系统中,对于键盘中断的处理优先级和对于电源掉电中断的处理优先级是不相同的。

•基于静态优先级的调度算法实现简单,系统开销小,但由于静态优先级一旦确定之后,直到执行结束为止始终保持不变,从而系统效率较低,调度性能不高。现在的操作系统中,如果使用优先级调度的话,则大多采用动态优先级的调度策略。

•进程的动态优先级一般可以根据以下两个方面来确定:

• (1)

根据进程占有

CPU

时间的长短来决定。一个进程占有处理机的时间愈长,则在被阻塞之后再次获得调度的优先级就越低。反之,其获得调度的可能性就会越大。

• (2)

根据就绪进程等待

CPU

的时间长短来决定。一个就绪进程在就绪队列中等待的时间越长,则它获得调度选中的优先级就越高。

•由于动态优先级随时间的推移而变化,系统要经常计算各个进程的优先级,因此,系统要为此付出一定的开销。

•最高优先级优先调度算法用于多道批处理系统中较好,但它使得优先级较低的进程等待时间较长,这对于分时系统中要想获得较好的响应时间是不允许的,所以在分时系统中多采用时间片轮转法来进行进程调度。

时间片轮转 (Round Robin

RR)

法 的基本思路是让每个进程在就绪队列中的等待时间与享受服务的时间成比例。在时间片轮转法中,需要将 CPU

的处理时间分成固定大小的时间片,例如,几十毫秒至几百毫秒。如果一个进程在被调度选中之后用完了系统规定的时间片,但又未完成要求的任务,则它自行释放自己所占有的

CPU

而排到就绪队列的末尾,等待下一次调度。同时,进程调度程序又去调度当前就绪队列中的第一个进程。

•显然,轮转法只能用来调度分配一些可以抢占的资源。这些可以抢占的资源可以随时被剥夺,而且可以将它们再分配给别的进程。 CPU

是可抢占资源的一种。但打印机等资源是不可抢占的。由于作业调度是对除了

CPU

之外的所有系统硬件资源的分配,其中包含有不可抢占资源,所以作业调度不使用轮转法。在轮转法中,时间片长度的选取非常重要。首先,时间片长度的选择会直接影响到系统的开销和响应时间。如果时间片长度过短,则调度程序抢占处理机的次数增多。这将使进程上下文切换次数也大大增加,从而加重系统开销。反过来,如果时间片长度选择过长,例如,一个时间片能保证就绪队列中所需执行时间最长的进程能执行完毕,则轮转法变成了先来先服务法。时间片长度的选择是根据系统对响应时间的要求和就绪队列中所允许最大的进程数来确定的。

• 在轮转法中,加入到就绪队列的进程有 3

种情况,一种是分给它的时间片用完,但进程还未完成,回到就绪队列的末尾等待下次调度去继续执行。另一种情况是分给该进程的时间片并未用完,只是因为请求

I/O

或由于进程的互斥与同步关系而被阻塞。当阻塞解除之后再回到就绪队列。第三种情况就是新创建进程进入就绪队列。如果对这些进程区别对待,给予不同的优先级和时间片,从直观上看,可以进一步改善系统服务质量和效率。例如,我们可把就绪队列按照进程到达就绪队列的类型和进程被阻塞时的阻塞原因分成不同的就绪队列,每个队列按

FCFS

原则排列,各队列之间的进程享有不同的优先级,但同一队列内优先级相同。这样,当一个进程在执行完它的时间片之后,或从睡眠中被唤醒以及被创建之后,将进入不同的就绪队列。

14. Windows 内存管理的方式

(

块式、页式、段式、段页式

).

内存管理是操作系统中的重要部分,两三句话恐怕谁也说不清楚吧~~我先说个大概,希望能够抛砖引玉吧 当程序运行时需要从内存中读出这段程序的代码。代码的位置必须在物理内存中才能被运行,由于现在的操作系统中有非常多的程序运行着,内存中不能够完全放下,所以引出了虚拟内存的概念。把哪些不常用的程序片断就放入虚拟内存,当需要用到它的时候在 load

入主存(物理内存)中。这个就是内存管理所要做的事。内存管理还有另外一件事需要做:计算程序片段在主存中的物理位置,以便

CPU

调度。 内存管理有块式管理,页式管理,段式和段页式管理。现在常用段页式管理

块式管理:

把主存分为一大块、一大块的,当所需的程序片断不在主存时就分配一块主存空间,把程序片断 load

入主存,就算所需的程序片度只有几个字节也只能把这一块分配给它。这样会造成很大的浪费,平均浪费了

50

%的内存空间,但是易于管理。

页式管理:

把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方法的空间利用率要比块式管理高很多。

段式管理:

把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上又比页式管理高很多,但是也有另外一个缺点。一个程序片断可能会被分为几十段,这样很多时间就会被浪费在计算每一段的物理地址上(计算机最耗时间的大家都知道是 I/O

吧)。

段页式管理:

结合了段式管理和页式管理的优点。将程序分成若干段,每个段分成若干页。

二维逻辑地址:段号 +

段内地址

分页与分段的主要区别:

1 )、段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。

2 )、页的大小固定不变,由系统决定。段的大小是不固定的,它由其完成的功能决定。

3 )、段式向用户提供的是二维地址空间,页式向用户提供的是一维地址空间,其页号和页内偏移是机器硬件的功能。

4 )、由于段是信息的逻辑单位,因此便于存贮保护和信息的共享,页的保护和共享受到限制。

分页与分段存储管理系统虽然在很多地方相似,但从概念上讲,两者是完全不同的,它们之间的区别如下:

页是信息的物理单位。分页的目的是实现离散分配,减少外部碎片,提高内存利用率。段是信息的逻辑单位。每一段在逻辑上是一组相对完整的信息集合。

分页式存储管理的作业地址空间是一维的,而分段式存储管理的作业地址空间是二维的。

页的大小固定且由系统确定,是等长的。而段的长度不定。

分页的优点体现在内存空间的管理上,而分段的优点体现在地址空间的管理上。

内存连续分配方式采用的几种算法及各自优劣。

单一连续分配

是一种最简单的存储管理方式,其优点是软件处理简单,最大缺点是存储器不能充分利用。多用于单用户微机操作系统中。

动态分区分配

是多道程序环境下各种存储管理方式中最简单的一种。它将内存划分成若干个分区,在每个分区中按照连续分配方式分配给一个作业。分区形式 :

a) 固定分区分配:

指内存在处理作业前已被划分成若干个大小不等的分区,存储管理程序根据每个作业步的最大存储量分配一个足够大的分区给它。当找不到一个足够大的分区时,则通知作业调度挑选另一作业,这种方式分配和回收内存简单,但内存利用不充分,会产生 “

碎片

空间。

b) 可变分区分配:

指内存事先并未被分区,只有当作业进入内存时,才根据作业的大小建立分区。其特点是分区的个数和大小都是可变的,但需要建立分配区表和空白区表,且表的长度是不固定的。

可重定位分区分配

为使各分区中的用户程序能移到内存的一端,使碎片集中于另一端成为一个大分区,在程序执行过程中,需对作业移动过程中的与地址有关项进行调整。这种分配方法的优点是清除碎片,更大程度地利用内存空间,但必须硬件的支持,且要花费时间。

动态链接及静态链接

.

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意, lib

中的指令都全部被直接包含在最终生成的

EXE

文件中了。但是若使用

DLL

,该

DLL

不必被包含在最终

EXE

文件中,

EXE

文件执行时可以“动态”地引用和卸载这个与

EXE

独立的

DLL

文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接 库

动态链接是指在生成可执行文件时不将所有程序用到的函数链接到一个文件,因为有许多函数在操作系统带的 dll

文件中,当程序运行时直接从操作系统中找。

而静态链接就是把所有用到的函数全部链接到 exe

文件中。

动态链接是只建立一个引用的接口,而真正的代码和数据存放在另外的可执行模块中,在运行时再装入;

而静态链接是把所有的代码和数据都复制到本模块中,运行时就不再需要库了。

基本分页、请求分页储存管理方式。 18.

基本分段、请求分段储存管理方式。

分页式存储管理的基本原理:采用分页存储器允许把一个作业存放到若干不相邻的分区中,既可免去移动信息的工作,又可尽量减少主存的碎片。分页式存储管理的基本原理如下:

1 、 页框:物理地址分成大小相等的许多区,每个区称为一块;

2 、址分成大小相等的区,区的大小与块的大小相等,每个称一个页面。

3 、 逻辑地址形式:与此对应,分页存储器的逻辑地址由两部分组成,页号和单元号。逻辑地址格式为

页号 单元号(页内地址)

采用分页式存储管理时,逻辑地址是连续的。所以,用户在编制程序时仍只须使用顺序的地址,而不必考虑如何去分页。

4 、页表和地址转换:如何保证程序正确执行呢?采用的办法是动态重定位技术,让程序的指令执行时作地址变换,由于程序段以页为单位,所以,我们给每个页设立一个重定位寄存器,这些重定位寄存器的集合便称页表。页表是操作系统为每个用户作业建立的,用来记录程序页面和主存对应页框的对照表,页表中的每一栏指明了程序中的一个页面和分得的页框的对应关系。绝对地址

=

块号

块长

单元号

以上从拓扑结构角度分析了对称式与非对称式虚拟存储方案的异同 ,

实际从虚拟化存储的实现原理来讲也有两种方式

;

即数据块虚拟与虚拟文件系统

.

数据块虚拟存储方案着重解决数据传输过程中的冲突和延时问题 .

在多交换机组成的大型

Fabric

结构的

SAN

,

由于多台主机通过多个交换机端口访问存储设备

,

延时和数据块冲突问题非常严重

.

数据块虚拟存储方案利用虚拟的多端口并行技术

,

为多台客户机提供了极高的带宽

,

最大限度上减少了延时与冲突的发生

,

在实际应用中

,

数据块虚拟存储方案以对称式拓扑结构为表现形式

.

虚拟文件系统存储方案着重解决大规模网络中文件共享的安全机制问题 .

通过对不同的站点指定不同的访问权限

,

保证网络文件的安全

.

在实际应用中

,

虚拟文件系统存储方案以非对称式拓扑结构为表现形式

.

虚拟存储技术 ,

实际上是虚拟存储技术的一个方面

,

特指以

CPU

时间和外存空间换取昂贵内存空间的操作系统中的资源转换技术

基本思想 :

程序

,

数据

,

堆栈的大小可以超过内存的大小

,

操作系统把程序当前使用的部分保留在内存

,

而把其他部分保存在磁盘上

,

并在需要时在内存和磁盘之间动态交换

,

虚拟存储器支持多道程序设计技术

目的 :

提高内存利用率

管理方式

A 请求式分页存储管理

在进程开始运行之前 ,

不是装入全部页面

,

而是装入一个或零个页面

,

之后根据进程运行的需要

,

动态装入其他页面

;

当内存空间已满

,

而又需要装入新的页面时

,

则根据某种算法淘汰某个页面

,

以便装入新的页面

B 请求式分段存储管理

为了能实现虚拟存储 ,

段式逻辑地址空间中的程序段在运行时并不全部装入内存

,

而是如同请求式分页存储管理

,

首先调入一个或若干个程序段运行

,

在运行过程中调用到哪段时

,

就根据该段长度在内存分配一个连续的分区给它使用

.

若内存中没有足够大的空闲分区

,

则考虑进行段的紧凑或将某段或某些段淘汰出去

,

这种存储管理技术称为请求式分段存储管理

分段分页方式的比较各自优缺点。

页和分段系统有许多相似之处,但在概念上两者完全不同,主要表现在:

1 、页是信息的物理单位,分页是为实现离散分配方式,以消减内存的外零头,提高内存的利用率;或者说,分页仅仅是由于系统管理的需要,而不是用户的需要。

段是信息的逻辑单位,它含有一组其意义相对完整的信息。分段的目的是为了能更好的满足用户的需要。

2 、页的大小固定且由系统确定,把逻辑地址划分为页号和页内地址两部分,是由机器硬件实现的,因而一个系统只能有一种大小的页面。

段的长度却不固定,决定于用户所编写的程序,通常由编辑程序在对源程序进行编辑时,根据信息的性质来划分。

3 、分页的作业地址空间是维一的,即单一的线性空间,程序员只须利用一个记忆符,即可表示一地址。

分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。

几种页面置换算法,会算所需换页数 。 (LRU

用程序如何实现?

)

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

1 )最佳置换算法(

OPT

)(理想置换算法)

这是一种理想情况下的页面置换算法,但实际上是不可能实现的。该算法的基本思想是:发生缺页时,有些页面在内存中,其中有一页将很快被访问(也包含紧接着的下一条指令的那页),而其他页面则可能要到 10

100

或者

1000

条指令后才会被访问,每个页面都可以用在该页面首次被访问前所要执行的指令数进行标记。最佳页面置换算法只是简单地规定:标记最大的页应该被置换。这个算法唯一的一个问题就是它无法实现。当缺页发生时,操作系统无法知道各个页面下一次是在什么时候被访问。虽然这个算法不可能实现,但是最佳页面置换算法可以用于对可实现算法的性能进行衡量比较。

2 )先进先出置换算法(

FIFO

最简单的页面置换算法是先入先出( FIFO

)法。这种算法的实质是,总是选择在主存中停留时间最长(即最老)的一页置换,即先进入内存的页,先退出内存。理由是:最早调入内存的页,其不再被使用的可能性比刚调入内存的可能性大。建立一个

FIFO

队列,收容所有在内存中的页。被置换页面总是在队列头上进行。当一个页面被放入内存时,就把它插在队尾上。

这种算法只是在按线性顺序访问地址空间时才是理想的,否则效率不高。因为那些常被访问的页,往往在主存中也停留得最久,结果它们因变“老”而不得不被置换出去。

FIFO 的另一个缺点是,它有一种异常现象,即在增加存储块的情况下,反而使缺页中断率增加了。当然,导致这种异常现象的页面走向实际上是很少见的。

3 )最近最久未使用(

LRU

)算法

FIFO 算法和

OPT

算法之间的主要差别是,

FIFO

算法利用页面进入内存后的时间长短作为置换依据,而

OPT

算法的依据是将来使用页面的时间。如果以最近的过去作为不久将来的近似,那么就可以把过去最长一段时间里不曾被使用的页面置换掉。它的实质是,当需要置换一页时,选择在最近一段时间里最久没有使用过的页面予以置换。这种算法就称为最久未使用算法(

Least Recently Used

LRU

)。

LRU 算法是与每个页面最后使用的时间有关的。当必须置换一个页面时,

LRU

算法选择过去一段时间里最久未被使用的页面。

LRU 算法是经常采用的页面置换算法,并被认为是相当好的,但是存在如何实现它的问题。

LRU

算法需要实际硬件的支持。其问题是怎么确定最后使用时间的顺序,对此有两种可行的办法:

计数器。最简单的情况是使每个页表项对应一个使用时间字段,并给

CPU

增加一个逻辑时钟或计数器。每次存储访问,该时钟都加

1

。每当访问一个页面时,时钟寄存器的内容就被复制到相应页表项的使用时间字段中。这样我们就可以始终保留着每个页面最后访问的“时间”。在置换页面时,选择该时间值最小的页面。这样做,不仅要查页表,而且当页表改变时(因

CPU

调度)要维护这个页表中的时间,还要考虑到时钟值溢出的问题。

栈。用一个栈保留页号。每当访问一个页面时,就把它从栈中取出放在栈顶上。这样一来,栈顶总是放有目前使用最多的页,而栈底放着目前最少使用的页。由于要从栈的中间移走一项,所以要用具有头尾指针的双向链连起来。在最坏的情况下,移走一页并把它放在栈顶上需要改动

6

个指针。每次修改都要有开销,但需要置换哪个页面却可直接得到,用不着查找,因为尾指针指向栈底,其中有被置换页。

因实现 LRU

算法必须有大量硬件支持,还需要一定的软件开销。所以实际实现的都是一种简单有效的

LRU

近似算法。

一种 LRU

近似算法是最近未使用算法(

Not Recently Used

NUR

)。它在存储分块表的每一表项中增加一个引用位,操作系统定期地将它们置为

0

。当某一页被访问时,由硬件将该位置

1

。过一段时间后,通过检查这些位可以确定哪些页使用过,哪些页自上次置

0

后还未使用过。就可把该位是

0

的页淘汰出去,因为在最近一段时间里它未被访问过。

4 )

Clock

置换算法(

LRU

算法的近似实现)

5 )最少使用(

LFU

)置换算法

在采用最少使用置换算法时,应为在内存中的每个页面设置一个移位寄存器,用来记录该页面被访问的频率。该置换算法选择在最近时期使用最少的页面作为淘汰页。由于存储器具有较高的访问速度,例如 100 ns

,在

1 ms

时间内可能对某页面连续访问成千上万次,因此,通常不能直接利用计数器来记录某页被访问的次数,而是采用移位寄存器方式。每次访问某页时,便将该移位寄存器的最高位置

1

,再每隔一定时间

(

例如

100 ns)

右移一次。这样,在最近一段时间使用最少的页面将是∑

Ri

最小的页。

LFU 置换算法的页面访问图与

LRU

置换算法的访问图完全相同;或者说,利用这样一套硬件既可实现

LRU

算法,又可实现

LFU

算法。应该指出,

LFU

算法并不能真正反映出页面的使用情况,因为在每一时间间隔内,只是用寄存器的一位来记录页的使用情况,因此,访问一次和访问

10 000

次是等效的。

虚拟内存的定义及实现方式。

虚拟内存,它的作用与物理内存基本相似,但它是作为物理内存的“后备力量”而存在的,也就是说,只有在物理内存已经不够使用的时候,它才会发挥作用。

改变页面文件位置的方法是:用鼠标右键点击“我的电脑”,选择“属性→高级→性能设置→高级→更改虚拟内存”,在驱动器栏里选择想要改变到的位置

操作系统的四个特性 。

并发性 ( concurrency

):指在计算机系统中存在着许多并发执行的活动。对计算机系统

而言,并发是指宏观上看系统内有多道程序同时运行,微观上看是串行运行。因为在

大多数计算机系统中一般只有一个

CPU

,在任意时刻只能有一道程序占用

CPU

共享性 ( sharing

):系统中各个并发活动要共享计算机系统中的各种软、硬件资源,因此操作系统必须解决在多道程序间合理地分配和使用资源问题。

虚拟性 ( virtual

):虚拟是操作系统中的重要特征,所谓虚拟是指把物理上的一台设备

变成逻辑上的多台设备。例如,在操作系统中采用了

spooling

技术,可以利用快速、

大容量可共享的磁盘作为中介,模拟多个非共享的低速的输入输出设备,这样的设备

称为虚拟设备。

异步性 :在多道程序环境下允许多个进程并发执行,但只有进程在获得所需的资源后方能执行。在单处理机环境下,由于系统中只有一台处理机,因而每次只允许一个进程执行,其余进程只能等待。

23. DMA 。

直接内存存取 (Direct Memory Access)

改善系统实时效能的一个熟知的方法是,额外提供一个逻辑模块,在事件发生时产生响应,并允许处理器在较方便的时间来处理信息。这个

DMA

控制器通常将传送到模块的信息复制到内存

(RAM)

,并允许已处理的信息自动从内存移到外部外围装置。所有这些工作皆独立于目前的

CPU

活动-详见图

1

这种方式肯定有所助益,但其效益仅限于延迟必然发生的事件- CPU

还是得在某一时间处理信息。

S12X

采用一个根本的方法,即提供「智能型

DMA

」控制器,不只移动资料,同时直接执行所有的处理工作。

24. Spooling 。

脱机输入和脱机输出

在多道环境下,可以用 OS

的一道管理程序实现从

I/O

设备输入数据并存放到磁盘上,模拟脱机输入;用

OS

的另一道管理程序将磁盘上的数据输出到

I/O

设备上,模拟脱机输出;这种假脱机

I/O

操作称为

Spooling

技术。

Spooling 是一种虚拟设备技术、一种资源转换技术。

外存分配的几种方式,及各种优劣。

连续分配:为每一个文件分配一组相邻接的盘块;物理上形成了顺序文件结构;外存上会出现 “

碎片

,用

紧凑

的方法解决。 优缺点:顺序(批量)访问容易、速度快;要求有连续的存储空间(有时需要作紧凑处理)、必须事先知道文件的长度。

链接分配:离散分配方式。优缺点:消除了 “

碎片

,有利于文件的增

/

/

改。隐式链接

在文件的每个目录项中,都含有指向链接文件第一盘块和最后一个盘块的指针,只适合于顺序访;显式链接,把用于链接文件各物理块的指针,显式地存放在内存的一张 “

链接表

中。

索引分配:单级索引分配每个文件一个索引块(表);多级索引分配当文件较大,需要很多个索引块时,可以为各索引块建立一个索引表(块);混合索引分配方式。