掌握這12個(gè)操作系統(tǒng)知識(shí)點(diǎn),把面試官按在地上摩擦
問(wèn)題一、操作系統(tǒng)的基本特征
1、并發(fā)
并發(fā)指一段時(shí)間內(nèi)能同時(shí)運(yùn)行多個(gè)程序,并行指同一時(shí)刻能運(yùn)行多個(gè)指令。操作系統(tǒng)通過(guò)引入進(jìn)程和線程,使得程序能夠并發(fā)運(yùn)行。
2、共享
共享是指系統(tǒng)中的資源可以被多個(gè)并發(fā)進(jìn)程共同使用。它主要有兩種共享方式:互斥共享和同時(shí)共享。多個(gè)應(yīng)用并發(fā)執(zhí)行的時(shí)候,宏觀上要體現(xiàn)出它們?cè)谕瑫r(shí)訪問(wèn)資源的情況,而微觀上要實(shí)現(xiàn)它們的互斥訪問(wèn)。比如說(shuō)我們說(shuō)到的內(nèi)存。
3、虛擬
虛擬技術(shù)把一個(gè)物理實(shí)體轉(zhuǎn)換為多個(gè)邏輯實(shí)體。利用多道程序設(shè)計(jì)技術(shù)(程序的交替運(yùn)行),讓每個(gè)用戶都覺(jué)得有一個(gè)計(jì)算機(jī)專門為他服務(wù)。主要有兩種虛擬技術(shù):時(shí)間復(fù)用技術(shù)和空間復(fù)用技術(shù)。
時(shí)間復(fù)用技術(shù)是指多個(gè)進(jìn)程能在同一個(gè)處理器上并發(fā)執(zhí)行,讓每個(gè)進(jìn)程輪流占用處理器,每次只執(zhí)行一小個(gè)時(shí)間片并快速切換。
空分復(fù)用技術(shù)值將物理內(nèi)存抽象為地址空間,每個(gè)進(jìn)程都有各自的地址空間。當(dāng)需要一個(gè)地址空間時(shí),如果沒(méi)有那就執(zhí)行頁(yè)面置換算法。
4、異步
異步指進(jìn)程不是一次性執(zhí)行完畢,而是走走停停,以不可知的速度向前推進(jìn)。但只要運(yùn)行的環(huán)境相同,OS需要保證程序運(yùn)行的結(jié)果也要相同。
問(wèn)題二、進(jìn)程與線程的本質(zhì)區(qū)別、以及各自的使用場(chǎng)景(重要)
1、進(jìn)程
進(jìn)程是資源分配的基本單位。就好比是手機(jī)上的一個(gè)個(gè)應(yīng)用程序。
2、線程
線程是獨(dú)立調(diào)度的基本單位。一個(gè)進(jìn)程中可以有多個(gè)線程,它們共享進(jìn)程資源。
3、進(jìn)程和線程的理解
QQ 和瀏覽器是兩個(gè)進(jìn)程,瀏覽器進(jìn)程里面有很多線程,例如 HTTP 請(qǐng)求線程、事件響應(yīng)線程、渲染線程等等,線程的并發(fā)執(zhí)行使得在瀏覽器中點(diǎn)擊一個(gè)新鏈接從而發(fā)起 HTTP 請(qǐng)求時(shí),瀏覽器還可以響應(yīng)用戶的其它事件。
4、進(jìn)程和線程的區(qū)別
(1)資源分配
進(jìn)程是資源分配的基本單位,但是線程不擁有資源,多個(gè)線程可以共享進(jìn)程資源。
(2)資源調(diào)度
在同一進(jìn)程中,線程的切換不會(huì)引起進(jìn)程切換,從一個(gè)進(jìn)程中的線程切換到另一個(gè)進(jìn)程中的線程時(shí),會(huì)引起進(jìn)程切換。就好比是打開了QQ,又打開了瀏覽器。
(3)系統(tǒng)開銷
線程不占用系統(tǒng)資源,比進(jìn)程開銷更小效率更高。這是因?yàn)閯?chuàng)建或撤銷進(jìn)程時(shí),系統(tǒng)都要為之分配或回收資源,如內(nèi)存空間、I/O 設(shè)備等,切換進(jìn)程時(shí)候,還要保存CPU狀態(tài)。
(4)對(duì)于一些要求同時(shí)進(jìn)行而又共享某些變量的并發(fā)操作來(lái)說(shuō),只能用多線程,不能用多進(jìn)程。
問(wèn)題三:進(jìn)程的幾種狀態(tài)
進(jìn)程主要是三種狀態(tài)。
(1)就緒。進(jìn)程已經(jīng)獲得了除CPU以外的所有所需資源,等待分配CPU資源
(2)運(yùn)行。已獲得了CPU資源,進(jìn)行運(yùn)行。處于運(yùn)行態(tài)的進(jìn)程數(shù)<=CPU核心數(shù)
(3)阻塞。進(jìn)程等待某些條件,在條件滿足前無(wú)法執(zhí)行
在這里我們最主要的是狀態(tài)之間的切換,比如說(shuō)阻塞狀態(tài)是不能到運(yùn)行狀態(tài)的。
問(wèn)題四:常見(jiàn)的進(jìn)程同步方式和線程同步方式
1、進(jìn)程同步的方式
(1)為什么要進(jìn)程同步
多進(jìn)程雖然提高了系統(tǒng)資源利用率和吞吐量,但是由于進(jìn)程的異步性可能造成系統(tǒng)的混亂。進(jìn)程同步的任務(wù)就是對(duì)多個(gè)相關(guān)進(jìn)程在執(zhí)行順序上進(jìn)行協(xié)調(diào),使并發(fā)執(zhí)行的多個(gè)進(jìn)程之間可以有效的共享資源和相互合作,保證程序執(zhí)行的可再現(xiàn)性。
(2)同步機(jī)制需要遵循的原則:
空閑讓進(jìn):當(dāng)沒(méi)有進(jìn)程處于臨界區(qū)的時(shí)候,應(yīng)該許可其他進(jìn)程進(jìn)入臨界區(qū)的申請(qǐng)
忙則等待:當(dāng)前如果有進(jìn)程處于臨界區(qū),如果有其他進(jìn)程申請(qǐng)進(jìn)入,則必須等待,保證對(duì)臨界區(qū)的互斥訪問(wèn)
有限等待:對(duì)要求訪問(wèn)臨界資源的進(jìn)程,需要在有限時(shí)間呃逆進(jìn)入臨界區(qū),防止出現(xiàn)死等
讓權(quán)等待:當(dāng)進(jìn)程無(wú)法進(jìn)入臨界區(qū)的時(shí)候,需要釋放處理機(jī),邊陷入忙等
(3)進(jìn)程同步的方式:原子操作、信號(hào)量、管程。
2、線程同步方式
(1)互斥(信號(hào))量,每個(gè)時(shí)刻只有一個(gè)線程可以訪問(wèn)公共資源。只有擁有互斥對(duì)象的線程才能訪問(wèn)公共資源,互斥對(duì)象只有一個(gè),一個(gè)時(shí)刻只能有一個(gè)線程持有,所以保證了公共資源不會(huì)被多個(gè)線程同時(shí)訪問(wèn)。
(2)信號(hào)量,允許多個(gè)線程同時(shí)訪問(wèn)公共資源。當(dāng)時(shí)控制了訪問(wèn)資源的線程的最大個(gè)數(shù)。
(3)事件 in windows(條件變量 in linux)。通過(guò)通知的方式保持多線程的同步,還可以方便的實(shí)現(xiàn)多線程優(yōu)先級(jí)的比較
(4)臨界區(qū)。任意時(shí)刻只能有一個(gè)線程進(jìn)入臨界區(qū),訪問(wèn)臨界資源。
問(wèn)題五、進(jìn)程間的通信方式
windows和linux是不一樣的。
問(wèn)題六、進(jìn)程任務(wù)調(diào)度算法的特點(diǎn)以及使用場(chǎng)景
(1)時(shí)間片輪轉(zhuǎn)調(diào)度算法(RR):給每個(gè)進(jìn)程固定的執(zhí)行時(shí)間,根據(jù)進(jìn)程到達(dá)的先后順序讓進(jìn)程在單位時(shí)間片內(nèi)執(zhí)行,執(zhí)行完成后便調(diào)度下一個(gè)進(jìn)程執(zhí)行,時(shí)間片輪轉(zhuǎn)調(diào)度不考慮進(jìn)程等待時(shí)間和執(zhí)行時(shí)間,屬于搶占式調(diào)度。優(yōu)點(diǎn)是兼顧長(zhǎng)短作業(yè);缺點(diǎn)是平均等待時(shí)間較長(zhǎng),上下文切換較費(fèi)時(shí)。適用于分時(shí)系統(tǒng)。
(2)先來(lái)先服務(wù)調(diào)度算法(FCFS):根據(jù)進(jìn)程到達(dá)的先后順序執(zhí)行進(jìn)程,不考慮等待時(shí)間和執(zhí)行時(shí)間,會(huì)產(chǎn)生饑餓現(xiàn)象。屬于非搶占式調(diào)度,優(yōu)點(diǎn)是公平,實(shí)現(xiàn)簡(jiǎn)單;缺點(diǎn)是不利于短作業(yè)。
(3)優(yōu)先級(jí)調(diào)度算法(HPF):在進(jìn)程等待隊(duì)列中選擇優(yōu)先級(jí)最高的來(lái)執(zhí)行。
(4)多級(jí)反饋隊(duì)列調(diào)度算法:將時(shí)間片輪轉(zhuǎn)與優(yōu)先級(jí)調(diào)度相結(jié)合,把進(jìn)程按優(yōu)先級(jí)分成不同的隊(duì)列,先按優(yōu)先級(jí)調(diào)度,優(yōu)先級(jí)相同的,按時(shí)間片輪轉(zhuǎn)。優(yōu)點(diǎn)是兼顧長(zhǎng)短作業(yè),有較好的響應(yīng)時(shí)間,可行性強(qiáng),適用于各種作業(yè)環(huán)境。
(5)高響應(yīng)比優(yōu)先調(diào)度算法:根據(jù)“響應(yīng)比=(進(jìn)程執(zhí)行時(shí)間+進(jìn)程等待時(shí)間)/ 進(jìn)程執(zhí)行時(shí)間”這個(gè)公式得到的響應(yīng)比來(lái)進(jìn)行調(diào)度。高響應(yīng)比優(yōu)先算法在等待時(shí)間相同的情況下,作業(yè)執(zhí)行的時(shí)間越短,響應(yīng)比越高,滿足段任務(wù)優(yōu)先,同時(shí)響應(yīng)比會(huì)隨著等待時(shí)間增加而變大,優(yōu)先級(jí)會(huì)提高,能夠避免饑餓現(xiàn)象。優(yōu)點(diǎn)是兼顧長(zhǎng)短作業(yè),缺點(diǎn)是計(jì)算響應(yīng)比開銷大,適用于批處理系統(tǒng)。
問(wèn)題七、死鎖的原因、必要條件、死鎖處理、手寫死鎖代碼、java是如何解決死鎖的
1、死鎖的原因
在兩個(gè)以上的并發(fā)進(jìn)程中,如果每個(gè)進(jìn)程都持有某種資源而又等待其他進(jìn)程釋放他們持有的資源,在未改變這種狀態(tài)前,誰(shuí)都無(wú)法推進(jìn),則發(fā)生了死鎖。就好比是對(duì)方相互拿著自己需要的資源,都不釋放自己的。
2、產(chǎn)生死鎖的四個(gè)必要條件
(1)互斥。一個(gè)資源一次只能被一個(gè)進(jìn)程占有
(2)請(qǐng)求與保持。一個(gè)進(jìn)程因?yàn)檎?qǐng)求資源而阻塞時(shí),不釋放自己持有的資源
(3)非剝奪。無(wú)法在進(jìn)程結(jié)束前剝奪它對(duì)資源的所有權(quán)
(4)循環(huán)等待。若干進(jìn)程收尾相接形成環(huán)形等待關(guān)系
3、死鎖處理
(1)預(yù)防死鎖。破壞后三個(gè)條件中的一個(gè)即可(互斥是非共享設(shè)備的特性,無(wú)法更改):
(2)死鎖避免。避免死鎖并不是事先采取某種限制措施破壞死鎖的必要條件,而是再資源動(dòng)態(tài)分配過(guò)程中,防止系統(tǒng)進(jìn)入不安全狀態(tài),以避免發(fā)生死鎖,比如銀行家算法、系統(tǒng)安全狀態(tài)、安全性算法。
(3)死鎖的檢測(cè)與解除:資源分配圖死鎖定理死鎖解除。
4、死鎖代碼
(1)使用信號(hào)量實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者
為了同步生產(chǎn)者和消費(fèi)者的行為,需要記錄緩沖區(qū)中物品的數(shù)量。數(shù)量可以使用信號(hào)量來(lái)進(jìn)行統(tǒng)計(jì),這里需要使用兩個(gè)信號(hào)量:empty 記錄空緩沖區(qū)的數(shù)量,full 記錄滿緩沖區(qū)的數(shù)量。其中,empty 信號(hào)量是在生產(chǎn)者進(jìn)程中使用,當(dāng) empty 不為 0 時(shí),生產(chǎn)者才可以放入物品;full 信號(hào)量是在消費(fèi)者進(jìn)程中使用,當(dāng) full 信號(hào)量不為 0 時(shí),消費(fèi)者才可以取走物品。
- #define N 100
- typedef int semaphore;
- semaphore mutex = 1;
- semaphore empty = N;
- semaphore full = 0;
- void producer() {
- while(TRUE) {
- int item = produce_item();
- down(&empty);
- down(&mutex);
- insert_item(item);
- up(&mutex);
- up(&full);
- }
- }
- void consumer() {
- while(TRUE) {
- down(&full);
- down(&mutex);
- int item = remove_item();
- consume_item(item);
- up(&mutex);
- up(&empty);
- }
- }
(2)使用管程實(shí)現(xiàn)生產(chǎn)者-消費(fèi)者
- // 管程
- monitor ProducerConsumer
- condition full, empty;
- integer count := 0;
- condition c;
- procedure insert(item: integer);
- begin
- if count = N then wait(full);
- insert_item(item);
- count := count + 1;
- if count = 1 then signal(empty);
- end;
- function remove: integer;
- begin
- if count = 0 then wait(empty);
- remove = remove_item;
- count := count - 1;
- if count = N -1 then signal(full);
- end;
- end monitor;
- // 生產(chǎn)者客戶端
- procedure producer
- begin
- while true do
- begin
- item = produce_item;
- ProducerConsumer.insert(item);
- end
- end;
- // 消費(fèi)者客戶端
- procedure consumer
- begin
- while true do
- begin
- item = ProducerConsumer.remove;
- consume_item(item);
- end
- end;
(3)讀寫問(wèn)題
允許多個(gè)進(jìn)程同時(shí)對(duì)數(shù)據(jù)進(jìn)行讀操作,但是不允許讀和寫以及寫和寫操作同時(shí)發(fā)生。一個(gè)整型變量 count 記錄在對(duì)數(shù)據(jù)進(jìn)行讀操作的進(jìn)程數(shù)量,一個(gè)互斥量 count_mutex 用于對(duì) count 加鎖,一個(gè)互斥量 data_mutex 用于對(duì)讀寫的數(shù)據(jù)加鎖。
- typedef int semaphore;
- semaphore count_mutex = 1;
- semaphore data_mutex = 1;
- int count = 0;
- void reader() {
- while(TRUE) {
- down(&count_mutex);
- count++;
- if(count == 1) down(&data_mutex); // 第一個(gè)讀者需要對(duì)數(shù)據(jù)進(jìn)行加鎖,防止寫進(jìn)程訪問(wèn)
- up(&count_mutex);
- read();
- down(&count_mutex);
- count--;
- if(count == 0) up(&data_mutex);
- up(&count_mutex);
- }
- }
- void writer() {
- while(TRUE) {
- down(&data_mutex);
- write();
- up(&data_mutex);
- }
- }
(4)哲學(xué)家就餐問(wèn)題
五個(gè)哲學(xué)家圍著一張圓桌,每個(gè)哲學(xué)家面前放著食物。哲學(xué)家的生活有兩種交替活動(dòng):吃飯以及思考。當(dāng)一個(gè)哲學(xué)家吃飯時(shí),需要先拿起自己左右兩邊的兩根筷子,并且一次只能拿起一根筷子。
下面是一種錯(cuò)誤的解法,考慮到如果所有哲學(xué)家同時(shí)拿起左手邊的筷子,那么就無(wú)法拿起右手邊的筷子,造成死鎖。
- #define N 5
- void philosopher(int i) {
- while(TRUE) {
- think();
- take(i); // 拿起左邊的筷子
- take((i+1)%N); // 拿起右邊的筷子
- eat();
- put(i);
- put((i+1)%N);
- }
- }
為了防止死鎖的發(fā)生,可以設(shè)置兩個(gè)條件:
- 必須同時(shí)拿起左右兩根筷子;
- 只有在兩個(gè)鄰居都沒(méi)有進(jìn)餐的情況下才允許進(jìn)餐。
- #define N 5
- #define LEFT (i + N - 1) % N // 左鄰居
- #define RIGHT (i + 1) % N // 右鄰居
- #define THINKING 0
- #define HUNGRY 1
- #define EATING 2
- typedef int semaphore;
- int state[N]; // 跟蹤每個(gè)哲學(xué)家的狀態(tài)
- semaphore mutex = 1; // 臨界區(qū)的互斥
- semaphore s[N]; // 每個(gè)哲學(xué)家一個(gè)信號(hào)量
- void philosopher(int i) {
- while(TRUE) {
- think();
- take_two(i);
- eat();
- put_two(i);
- }
- }
- void take_two(int i) {
- down(&mutex);
- state[i] = HUNGRY;
- test(i);
- up(&mutex);
- down(&s[i]);
- }
- void put_two(i) {
- down(&mutex);
- state[i] = THINKING;
- test(LEFT);
- test(RIGHT);
- up(&mutex);
- }
- void test(i) { // 嘗試拿起兩把筷子
- if(state[i] == HUNGRY && state[LEFT] != EATING && state[RIGHT] !=EATING) {
- state[i] = EATING;
- up(&s[i]);
- }
- }
問(wèn)題八:線程實(shí)現(xiàn)的兩種方式,各有什么優(yōu)缺點(diǎn)
問(wèn)題九、內(nèi)存管理的方式:段式、頁(yè)式、段頁(yè)式。比較他們的區(qū)別
操作系統(tǒng)中的內(nèi)存管理有三種,段式頁(yè)式段頁(yè)式。
1、為什么需要三種管理方式
由于連續(xù)內(nèi)存分配方式會(huì)導(dǎo)致內(nèi)存利用率偏低以及內(nèi)存碎片的問(wèn)題,因此需要對(duì)這些離散的內(nèi)存進(jìn)行管理。引出了三種內(nèi)存管理方式。
2、分頁(yè)存儲(chǔ)管理
(1)基本分頁(yè)存儲(chǔ)管理中不具備頁(yè)面置換功能,因此需要整個(gè)程序的所有頁(yè)面都裝入內(nèi)存之后才可以運(yùn)行。
(2)需要一個(gè)頁(yè)表來(lái)記錄邏輯地址和實(shí)際存儲(chǔ)地址之間的映射關(guān)系,以實(shí)現(xiàn)從頁(yè)號(hào)到物理塊號(hào)的映射。
(3)由于頁(yè)表也是存儲(chǔ)在內(nèi)存中的,因此內(nèi)存數(shù)據(jù)需要兩次的內(nèi)存訪問(wèn)(一次是從內(nèi)存中訪問(wèn)頁(yè)表,從中找到指定的物理塊號(hào),加上頁(yè)內(nèi)偏移得到實(shí)際物理地址;第二次就是根據(jù)第一次得到的物理地址訪問(wèn)內(nèi)存取出數(shù)據(jù))。
(4)為了減少兩次訪問(wèn)內(nèi)存導(dǎo)致的效率影響,分頁(yè)管理中引入了快表,當(dāng)要訪問(wèn)內(nèi)存數(shù)據(jù)的時(shí)候,首先將頁(yè)號(hào)在快表中查詢,如果在快表中,直接讀取相應(yīng)的物理塊號(hào);如果沒(méi)有找到,那么訪問(wèn)內(nèi)存中的頁(yè)表,從頁(yè)表中得到物理地址,同時(shí)將頁(yè)表中的該映射表項(xiàng)添加到快表中。
(5)在某些計(jì)算機(jī)中如果內(nèi)存的邏輯地址很大,將會(huì)導(dǎo)致程序的頁(yè)表項(xiàng)會(huì)很多,而頁(yè)表在內(nèi)存中是連續(xù)存放的,所以相應(yīng)的就需要較大的連續(xù)內(nèi)存空間。為了解決這個(gè)問(wèn)題,可以采用兩級(jí)頁(yè)表或者多級(jí)頁(yè)表的方法,其中外層頁(yè)表一次性調(diào)入內(nèi)存且連續(xù)存放,內(nèi)層頁(yè)表離散存放。相應(yīng)的訪問(wèn)內(nèi)存頁(yè)表的時(shí)候需要一次地址變換,訪問(wèn)邏輯地址對(duì)應(yīng)的物理地址的時(shí)候也需要一次地址變換,而且一共需要訪問(wèn)內(nèi)存3次才可以讀取一次數(shù)據(jù)。
3、分段存儲(chǔ)管理
分頁(yè)是為了提高內(nèi)存利用率,而分段是為了滿足程序員在編寫代碼的時(shí)候的一些邏輯需求(比如數(shù)據(jù)共享,數(shù)據(jù)保護(hù),動(dòng)態(tài)鏈接等)。
(1)分段內(nèi)存管理當(dāng)中,地址是二維的,一維是段號(hào),一維是段內(nèi)地址;
(2)其中每個(gè)段的長(zhǎng)度是不一樣的,而且每個(gè)段內(nèi)部都是從0開始編址的。由于分段管理中,每個(gè)段內(nèi)部是連續(xù)內(nèi)存分配,但是段和段之間是離散分配的,因此也存在一個(gè)邏輯地址到物理地址的映射關(guān)系,相應(yīng)的就是段表機(jī)制。段表中的每一個(gè)表項(xiàng)記錄了該段在內(nèi)存中的起始地址和該段的長(zhǎng)度。段表可以放在內(nèi)存中也可以放在寄存器中。
(3)訪問(wèn)內(nèi)存的時(shí)候根據(jù)段號(hào)和段表項(xiàng)的長(zhǎng)度計(jì)算當(dāng)前訪問(wèn)段在段表中的位置,然后訪問(wèn)段表,得到該段的物理地址,根據(jù)該物理地址以及段內(nèi)偏移量就可以得到需要訪問(wèn)的內(nèi)存。由于也是兩次內(nèi)存訪問(wèn),所以分段管理中同樣引入了聯(lián)想寄存器。
4、分段和分頁(yè)的對(duì)比
(1)頁(yè)是信息的物理單位,是出于系統(tǒng)內(nèi)存利用率的角度提出的離散分配機(jī)制;段是信息的邏輯單位,每個(gè)段含有一組意義完整的信息,是出于用戶角度提出的內(nèi)存管理機(jī)制
(2)頁(yè)的大小是固定的,由系統(tǒng)決定;段的大小是不確定的,由用戶決定
(3)頁(yè)地址空間是一維的,段地址空間是二維的
5、段頁(yè)存儲(chǔ)方式
先將用戶程序分為若干個(gè)段,然后再把每個(gè)段分成若干個(gè)頁(yè),并且為每一個(gè)段賦予一個(gè)段名稱。這樣在段頁(yè)式管理中,一個(gè)內(nèi)存地址就由段號(hào),段內(nèi)頁(yè)號(hào)以及頁(yè)內(nèi)地址三個(gè)部分組成。
段頁(yè)式內(nèi)存訪問(wèn):系統(tǒng)中設(shè)置了一個(gè)段表寄存器,存放段表的起始地址和段表的長(zhǎng)度。地址變換時(shí),根據(jù)給定的段號(hào)(還需要將段號(hào)和寄存器中的段表長(zhǎng)度進(jìn)行比較防止越界)以及寄存器中的段表起始地址,就可以得到該段對(duì)應(yīng)的段表項(xiàng),從段表項(xiàng)中得到該段對(duì)應(yīng)的頁(yè)表的起始地址,然后利用邏輯地址中的段內(nèi)頁(yè)號(hào)從頁(yè)表中找到頁(yè)表項(xiàng),從該頁(yè)表項(xiàng)中的物理塊地址以及邏輯地址中的頁(yè)內(nèi)地址拼接出物理地址,最后用這個(gè)物理地址訪問(wèn)得到所需數(shù)據(jù)。由于訪問(wèn)一個(gè)數(shù)據(jù)需要三次內(nèi)存訪問(wèn),所以段頁(yè)式管理中也引入了高速緩沖寄存器。
問(wèn)題十、虛擬內(nèi)存的作用
1、虛擬內(nèi)存存在的意義?
(1)既然每個(gè)進(jìn)程的內(nèi)存空間都是一致而且固定的,所以鏈接器在鏈接可執(zhí)行文件時(shí),可以設(shè)定內(nèi)存地址,而不用去管這些數(shù)據(jù)最終實(shí)際的內(nèi)存地址,這是有獨(dú)立內(nèi)存空間的好處
(2)當(dāng)不同的進(jìn)程使用同樣的代碼時(shí),比如庫(kù)文件中的代碼,物理內(nèi)存中可以只存儲(chǔ)一份這樣的代碼,不同的進(jìn)程只需要把自己的虛擬內(nèi)存映射過(guò)去就可以了,節(jié)省內(nèi)存
(3)在程序需要分配連續(xù)的內(nèi)存空間的時(shí)候,只需要在虛擬內(nèi)存空間分配連續(xù)空間,而不需要實(shí)際物理內(nèi)存的連續(xù)空間,可以利用碎片。
2、虛擬內(nèi)存和物理內(nèi)存的關(guān)系
問(wèn)題十一、頁(yè)面置換算法
1、算法講解
(1)最佳置換算法:理想的置換算法。置換策略是將當(dāng)前頁(yè)面中在未來(lái)最長(zhǎng)時(shí)間內(nèi)不會(huì)被訪問(wèn)的頁(yè)置換出去。
(2)先進(jìn)先出置換算法:每次淘汰最早調(diào)入的頁(yè)面 。
(3)最近最久未使用算法LRU:每次淘汰最久沒(méi)有使用的頁(yè)面。使用了一個(gè)時(shí)間標(biāo)志。
(4)時(shí)鐘算法clock(最近未使用算法NRU):頁(yè)面設(shè)置一個(gè)訪問(wèn)位,并將頁(yè)面鏈接為一個(gè)環(huán)形隊(duì)列,頁(yè)面被訪問(wèn)的時(shí)候訪問(wèn)位設(shè)置為1。頁(yè)面置換的時(shí)候,如果當(dāng)前指針?biāo)疙?yè)面訪問(wèn)為為0,那么置換,否則將其置為0,循環(huán)直到遇到一個(gè)訪問(wèn)為位0的頁(yè)面
(5)改進(jìn)型Clock算法:在Clock算法的基礎(chǔ)上添加一個(gè)修改位,替換時(shí)根究訪問(wèn)位和修改位綜合判斷。優(yōu)先替換訪問(wèn)為何修改位都是0的頁(yè)面,其次是訪問(wèn)位為0修改位為1的頁(yè)面。
(6)最少使用算法LFU:設(shè)置寄存器記錄頁(yè)面被訪問(wèn)次數(shù),每次置換的時(shí)候置換當(dāng)前訪問(wèn)次數(shù)最少的。LFU和LRU是很類似的,支持硬件也是一樣的,但是區(qū)分兩者的關(guān)鍵在于一個(gè)以時(shí)間為標(biāo)準(zhǔn),一個(gè)以次數(shù)為標(biāo)準(zhǔn)。
(7)頁(yè)面緩沖算法PBA:置換的時(shí)候,頁(yè)面無(wú)論是否被修改過(guò),都不被置換到磁盤,而是先暫留在內(nèi)存中的頁(yè)面鏈表里面,當(dāng)其再次被訪問(wèn)的時(shí)候可以直接從這些鏈表中取出而不必進(jìn)行磁盤IO,當(dāng)鏈表中已修改也難數(shù)目達(dá)到一定數(shù)量之后,進(jìn)行依次寫磁盤操作。
2、java實(shí)現(xiàn)LRU算法
- public class LRU {
- public static void main(String[] args) {
- String[] inputStr = {"6", "7", "6", "5", "9", "6", "8", "9", "7", "6", "9", "6"};
- // 內(nèi)存塊
- int memory = 3;
- List<String> list = new ArrayList<>();
- for(int i = 0; i < inputStr.length; i++){
- if(i == 0){
- list.add(inputStr[i]);
- System.out.println("第"+ i +"次訪問(wèn):\t\t" + ListUtils.listToString(list));
- }else {
- if(ListUtils.find(list, inputStr[i])){
- // 存在字符串,則獲取該下標(biāo)
- int index = ListUtils.findIndex(list, inputStr[i]);
- // 下標(biāo)不位于棧頂時(shí),且list大小不為1時(shí)
- if(!(list.get(list.size() - 1)).equals(inputStr[i]) && list.size() != 1) {
- String str = list.get(index);
- list.remove(index);
- list.add(str);
- }
- System.out.println("第" + i + "次" + "訪問(wèn):\t\t" + ListUtils.listToString(list));
- }else{
- if(list.size()>= memory) {
- list.remove(0);
- list.add(inputStr[i]);
- System.out.println("第" + i + "次" + "訪問(wèn):\t\t" + ListUtils.listToString(list));
- }else {
- list.add(inputStr[i]);
- System.out.println("第" + i + "次" + "訪問(wèn):\t\t" + ListUtils.listToString(list));
- }
- }
- }
- }
- }
- }
問(wèn)題十二、靜態(tài)鏈接和動(dòng)態(tài)鏈接
應(yīng)用程序有兩種鏈接方式,一種是靜態(tài)鏈接,一種是動(dòng)態(tài)鏈接。
1、基本概念
所謂靜態(tài)鏈接就是在編譯鏈接時(shí)直接將需要的執(zhí)行代碼拷貝到調(diào)用處,優(yōu)點(diǎn)就是在程序發(fā)布的時(shí)候就不需要的依賴庫(kù),也就是不再需要帶著庫(kù)一塊發(fā)布,程序可以獨(dú)立執(zhí)行,但是體積可能會(huì)相對(duì)大一些。
所謂動(dòng)態(tài)鏈接就是在編譯的時(shí)候不直接拷貝可執(zhí)行代碼,而是通過(guò)記錄一系列符號(hào)和參數(shù),在程序運(yùn)行或加載時(shí)將這些信息傳遞給操作系統(tǒng),操作系統(tǒng)負(fù)責(zé)將需要的動(dòng)態(tài)庫(kù)加載到內(nèi)存中,然后程序在運(yùn)行到指定的代碼時(shí),去共享執(zhí)行內(nèi)存中已經(jīng)加載的動(dòng)態(tài)庫(kù)可執(zhí)行代碼,最終達(dá)到運(yùn)行時(shí)連接的目的。
2、windows和linux區(qū)別
windows:
在windows上大家都是DLL是動(dòng)態(tài)鏈接庫(kù),里面是一系列可執(zhí)行的代碼,開發(fā)過(guò)windows程序的人可能還知道有另外一種形式的庫(kù),就是LIB,大家可能普遍認(rèn)為L(zhǎng)IB就是靜態(tài)庫(kù),至少我之前是這么認(rèn)為的,但是在實(shí)際的開發(fā)過(guò)程中,糾正了我這個(gè)錯(cuò)誤的想法。LIB形式的文件可能會(huì)有兩種形式,這里并不排除第三種形式。1:包括符號(hào)表和二進(jìn)制可執(zhí)行代碼,也就是傳統(tǒng)意義上理解的靜態(tài)庫(kù),可以被靜態(tài)連接。2:只有符號(hào)表,也就是只有動(dòng)態(tài)庫(kù)的符號(hào)導(dǎo)出信息,通過(guò)這些信息可以在程序運(yùn)行時(shí)定位到動(dòng)態(tài)庫(kù)中,最終實(shí)現(xiàn)動(dòng)態(tài)連接。
linux:
在linux上大家也都知道SO是動(dòng)態(tài)庫(kù),類似于windows下的DLL,實(shí)現(xiàn)方式也是大同小異,同時(shí)開發(fā)過(guò)linux下程序的人也都知道另外一種形式的庫(kù)就是A庫(kù),同樣道理普遍認(rèn)為是和SO對(duì)立的,也就是靜態(tài)庫(kù),不然沒(méi)道理存在啊,呵呵。但是事實(shí)區(qū)卻不是如此,A文件的作用和windows下的LIB文件作用幾乎一樣,也可能會(huì)有兩種形式,和windows下的lib文件一樣,在此就不在贅述。
3、靜態(tài)鏈接庫(kù)的優(yōu)點(diǎn)
(1) 代碼裝載速度快,執(zhí)行速度略比動(dòng)態(tài)鏈接庫(kù)快;
(2) 只需保證在開發(fā)者的計(jì)算機(jī)中有正確的.LIB文件,在以二進(jìn)制形式發(fā)布程序時(shí)不需考慮在用戶的計(jì)算機(jī)上.LIB文件是否存在及版本問(wèn)題,可避免DLL地獄等問(wèn)題。
4、動(dòng)態(tài)鏈接庫(kù)的優(yōu)點(diǎn)
(1) 更加節(jié)省內(nèi)存并減少頁(yè)面交換;
(2) DLL文件與EXE文件獨(dú)立,只要輸出接口不變(即名稱、參數(shù)、返回值類型和調(diào)用約定不變),更換DLL文件不會(huì)對(duì)EXE文件造成任何影響,因而極大地提高了可維護(hù)性和可擴(kuò)展性;
(3) 不同編程語(yǔ)言編寫的程序只要按照函數(shù)調(diào)用約定就可以調(diào)用同一個(gè)DLL函數(shù);
(4)適用于大規(guī)模的軟件開發(fā),使開發(fā)過(guò)程獨(dú)立、耦合度小,便于不同開發(fā)者和開發(fā)組織之間進(jìn)行開發(fā)和測(cè)試。
5、不足之處
(1) 使用靜態(tài)鏈接生成的可執(zhí)行文件體積較大,包含相同的公共代碼,造成浪費(fèi);
(2) 使用動(dòng)態(tài)鏈接庫(kù)的應(yīng)用程序不是自完備的,它依賴的DLL模塊也要存在,如果使用載入時(shí)動(dòng)態(tài)鏈接,程序啟動(dòng)時(shí)發(fā)現(xiàn)DLL不存在,系統(tǒng)將終止程序并給出錯(cuò)誤信息。而使用運(yùn)行時(shí)動(dòng)態(tài)鏈接,系統(tǒng)不會(huì)終止,但由于DLL中的導(dǎo)出函數(shù)不可用,程序會(huì)加載失敗;速度比靜態(tài)鏈接慢。當(dāng)某個(gè)模塊更新后,如果新模塊與舊的模塊不兼容,那么那些需要該模塊才能運(yùn)行的軟件,統(tǒng)統(tǒng)撕掉。這在早期Windows中很常見(jiàn)。
本文轉(zhuǎn)載自微信公眾號(hào)「愚公要移山」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系愚公要移山公眾號(hào)。