進程有那些狀態(tài)?
答:
- 創(chuàng)建狀態(tài)(new) :進程正在被創(chuàng)建俗批,尚未到就緒狀態(tài)。
- 就緒狀態(tài)(ready) :進程已處于準備運行狀態(tài)辛慰,即進程獲得了除了處理器之外的一切所需資源干像,一旦得到處理器資源(處理器分配的時間片)即可運行。
- 運行狀態(tài)(running) :進程正在處理器上上運行(單核 CPU 下任意時刻只有一個進程處于運行狀態(tài))速客。
- 阻塞狀態(tài)(waiting) :又稱為等待狀態(tài)溺职,進程正在等待某一事件而暫停運行如等待某資源為可用或等待 IO 操作完成。即使處理器空閑乱灵,該進程也不能運行七冲。
- 結束狀態(tài)(terminated) :進程正在從系統(tǒng)中消失澜躺。可能是進程正常結束或其他原因中斷退出運行耘戚。
進程間的通信方式
1. 管道/匿名管道(Pipes) :用于具有親緣關系的父子進程間或者兄弟進程之間的通信通铲。
2. 有名管道(Names Pipes) : 匿名管道由于沒有名字颅夺,只能用于親緣關系的進程間通信。為了克服這個缺點部服,提出了有名管道拗慨。有名管道嚴格遵循先進先出(first in first out)赵抢。有名管道以磁盤文件的方式存在,可以實現(xiàn)本機任意兩個進程通信宠叼。
3. 信號(Signal) :信號是一種比較復雜的通信方式,用于通知接收進程某個事件已經(jīng)發(fā)生伸蚯;
4. 消息隊列(Message Queuing) :消息隊列是消息的鏈表,具有特定的格式,存放在內存中并由消息隊列標識符標識简烤。管道和消息隊列的通信數(shù)據(jù)都是先進先出的原則横侦。與管道(無名管道:只存在于內存中的文件;命名管道:存在于實際的磁盤介質或者文件系統(tǒng))不同的是消息隊列存放在內核中瑞眼,只有在內核重啟(即棵逊,操作系統(tǒng)重啟)或者顯示地刪除一個消息隊列時银酗,該消息隊列才會被真正的刪除。消息隊列可以實現(xiàn)消息的隨機查詢,消息不一定要以先進先出的次序讀取,也可以按消息的類型讀取.比 FIFO 更有優(yōu)勢蛙讥。消息隊列克服了信號承載信息量少次慢,管道只能承載無格式字 節(jié)流以及緩沖區(qū)大小受限等缺翔曲。
5. 信號量(Semaphores) :信號量是一個計數(shù)器瞳遍,用于多進程對共享數(shù)據(jù)的訪問,信號量的意圖在于進程間同步由缆。這種通信方式主要用于解決與同步相關的問題并避免競爭條件猾蒂。
6. 共享內存(Shared memory) :使得多個進程可以訪問同一塊內存空間,不同進程可以及時看到對方進程中對共享內存中數(shù)據(jù)的更新舔箭。這種方式需要依靠某種同步操作限嫌,如互斥鎖和信號量等÷悖可以說這是最有用的進程間通信方式焰薄。
7. 套接字(Sockets) :此方法主要用于在客戶端和服務器之間通過網(wǎng)絡進行通信扒袖。套接字是支持 TCP/IP 的網(wǎng)絡通信的基本操作單元,可以看做是不同主機之間的進程進行雙向通信的端點野瘦,簡單的說就是通信的兩方的一種約定鞭光,用套接字中的相關函數(shù)來完成通信過程泞遗。
線程之間的通信方式史辙?
答:
1. 共享內存:線程之間共享程序的公共狀態(tài),線程之間通過讀-寫內存中的公共狀態(tài)來隱式通信晦毙。volatile共享內存
2. 消息傳遞:線程之間沒有公共的狀態(tài)方库,線程之間必須通過明確的發(fā)送信息來顯示的進行通信纵潦。wait/notify等待通知方式、join方式
3. 使用阻塞隊列控制線程通信:管道輸入/輸出流的形式
4.使用管道流進行線程通信(已被上面的阻塞隊列代替)
通過輸入/輸出在線程間進行通信通常很有用返敬。Java中對應的實現(xiàn)就是PipedWriter類和PipedReader類劲赠。這種使用管道來通信的模型可以看成是"生產(chǎn)者-消費者"問題的變種,這里的管道就是一個封裝好的解決方案霹肝。管道基本上就是一個阻塞隊列塑煎,它存在于引入阻塞隊列之前的java版本中最铁。在實際開發(fā)中,很少會使用到管道流漱挎。
用戶級線程和內核級線程磕谅?
線程的同步方式雾棺?
1. 互斥量(Mutex):采用互斥對象機制,只有擁有互斥對象的線程才有訪問公共資源的權限。因為互斥對象只有一個嘉栓,所以可以保證公共資源不會被多個線程同時訪問侵佃。比如 Java 中的 synchronized 關鍵詞和各種 Lock 都是這種機制奠支。
2. 信號量(Semphares) :它允許同一時刻多個線程訪問同一資源倍谜,但是需要控制同一時刻訪問此資源的最大線程數(shù)量
3. 事件(Event) :Wait/Notify:通過通知操作的方式來保持多線程同步,還可以方便的實現(xiàn)多線程優(yōu)先級的比較操
操作系統(tǒng)中進程的調度算法有哪些嗎?
- 先到先服務(FCFS)調度算法 : 從就緒隊列中選擇一個最先進入該隊列的進程為之分配資源答毫,使它立即執(zhí)行并一直執(zhí)行到完成或發(fā)生某事件而被阻塞放棄占用 CPU 時再重新調度洗搂。
- 短作業(yè)優(yōu)先(SJF)的調度算法 : 從就緒隊列中選出一個估計運行時間最短的進程為之分配資源,使它立即執(zhí)行并一直執(zhí)行到完成或發(fā)生某事件而被阻塞放棄占用 CPU 時再重新調度撵颊。
- 時間片輪轉調度算法 :時間片輪轉調度是一種最古老倡勇,最簡單挣棕,最公平且使用最廣的算法洛心,又稱 RR(Round robin)調度。每個進程被分配一個時間段厅目,稱作它的時間片法严,即該進程允許運行的時間深啤。
- 優(yōu)先級調度 : 為每個流程分配優(yōu)先級溯街,首先執(zhí)行具有最高優(yōu)先級的進程酵紫,依此類推验庙。具有相同優(yōu)先級的進程以 FCFS 方式執(zhí)行僧界〉5校可以根據(jù)內存要求辞槐,時間要求或任何其他資源要求來確定優(yōu)先級催蝗。
- 多級反饋隊列調度算法 :前面介紹的幾種進程調度的算法都有一定的局限性育特。如短進程優(yōu)先的調度算法,僅照顧了短進程而忽略了長進程 犬缨。多級反饋隊列調度算法既能使高優(yōu)先級的作業(yè)得到響應又能使短作業(yè)(進程)迅速完成怀薛。枝恋,因而它是目前被公認的一種較好的進程調度算法,UNIX 操作系統(tǒng)采取的便是這種調度算法畦攘。
過程:
1知押、按照先來先服務原則排序鹃骂,設置N個就緒隊列為Q1畏线,Q2...QN,每個隊列中都可以放很多作業(yè)温亲;
2、為這N個就緒隊列賦予不同的優(yōu)先級袖外,第一個隊列的優(yōu)先級最高曼验,第二個隊列次之鬓照,其余各隊列的優(yōu)先權逐個降低;
3拒秘、設置每個就緒隊列的時間片躺酒,優(yōu)先權越高,算法賦予隊列的時間片越小揽碘。時間片大小的設定按照實際作業(yè)(進程)的需要調整雳刺;
4裸违、進程在進入待調度的隊列等待時累颂,首先進入優(yōu)先級最高的Q1等待。
5料饥、首先調度優(yōu)先級高的隊列中的進程岸啡。若高優(yōu)先級中隊列中已沒有調度的進程巡蘸,則調度次優(yōu)先級隊列中的進程擂送。例如:Q1,Q2,Q3三個隊列嘹吨,只有在Q1中沒有進程等待時才去調度Q2,同理碰纬,只有Q1,Q2都為空時才會去調度Q3悦析。
6强戴、對于同一個隊列中的各個進程,按照時間片輪轉法調度媒佣。比如Q1隊列的時間片為N默伍,那么Q1中的作業(yè)在經(jīng)歷了時間片為N的時間后衰琐,若還沒有完成羡宙,則進入Q2隊列等待,若Q2的時間片用完后作業(yè)還不能完成钞馁,一直進入下一級隊列僧凰,直至完成训措。
7光羞、在低優(yōu)先級的隊列中的進程在運行時纱兑,又有新到達的作業(yè)潜慎,那么在運行完這個時間片后,CPU馬上分配給新到達的作業(yè)即搶占式調度CPU勘纯。
多線程和多進程區(qū)別?
答:
線程(CPU調度和分派的基本單位)是進程(操作系統(tǒng)進行資源分配和調度的基本單位)劃分成的更小的運行單位,一個進程在其執(zhí)行的過程中可以產(chǎn)生多個線程钓瞭。線程和進程最大的不同在于基本上各進程是獨立的驳遵,而各線程則不一定,因為同一進程中的線程極有可能會相互影響山涡。線程執(zhí)行開銷小堤结,但不利于資源的管理和保護唆迁;而進程正相反,并且線程中內存地址空間是相互共享的竞穷,而進程中不是。因此瘾带,進程和線程其實都是內核調度實體(KSE)鼠哥,只是對?些系統(tǒng)資源,例如虛擬內存看政、打開?件描述符朴恳、對信號的處置、進程 ID 等資源的共享程度不同?已允蚣。所以我們可以推斷出以下結論:
- 線程間的通信更容易于颖,因為擁有著同?塊數(shù)據(jù)段,因?可以使?全局變量進?通信嚷兔,相當于繼承森渐,大家公用一部分資源。
- 線程的創(chuàng)建速度要高于進程冒晰,因為“數(shù)據(jù)重合度”更?同衣,?線程只需要擁有??的程序計數(shù)器,一組寄存器和棧即可(1、程序計數(shù)器為什么是私有的?程序計數(shù)器私有主要是為了線程切換后能恢復到正確的執(zhí)行位置翩剪。2乳怎、棧為什么是私有的?保證線程中的局部變量不被別的線程訪問到前弯,虛擬機棧和本地方法棧是線程私有的蚪缀。)
- 線程之間的上下?切換也要?進程間的上下?切換更快,因為線程更加輕量恕出,自然在切換的過程中消耗的資源也更少(什么是上下文切換?線程切換意味著需要保存當前線程的上下文询枚,留待線程下次占用 CPU 的時候恢復現(xiàn)場。并加載下一個將要占用 CPU 的線程上下文浙巫。這就是所謂的 上下文切換金蜀。)。
- 線程同步的時候需要同步機制來支持的畴,因為資源共享渊抄,我們在共享資源操作的時候,需要加額外的操作丧裁,但是進程不用护桦,進程的資源是獨立的,同步的時候更加容易
協(xié)程和線程區(qū)別煎娇?
答:
- 概念:協(xié)程是一種比線程更加輕量級的存在二庵,一個線程可以擁有多個協(xié)程贪染。協(xié)程不是被操作系統(tǒng)內核所管理,而是完全由程序所控制(也就是在用戶態(tài)執(zhí)行)催享,好處是性能得到了很大提升杭隙,不會像線程切換那樣消耗資源。協(xié)程擁有自己的寄存器上下文和棧因妙。協(xié)程調度切換時痰憎,將寄存器上下文和棧保存到其他地方,在切回來的時候兰迫,恢復先前保存的寄存器上下文和棧信殊。因此:協(xié)程能保留上一次調用時的狀態(tài)(即所有局部狀態(tài)的一個特定組合),每次過程重入時汁果,就相當于進入上一次調用的狀態(tài)涡拘,換種說法:進入上一次離開時所處邏輯流的位置。
-
協(xié)程的好處:
無需線程上下文切換的開銷(無需切換內核態(tài)與用戶態(tài))
無需原子操作鎖定及同步的開銷
方便切換控制流据德,簡化編程模型
線程進程都是同步機制鳄乏,而協(xié)程則是異步。 -
應用場景:可以在線程IO阻塞的時候棘利,去運行協(xié)程橱野,提高CPU利用率
什么是協(xié)程?(參考鏈接)
并發(fā)和并行的區(qū)別
-
并發(fā):
并發(fā)(Concurrent)善玫,在操作系統(tǒng)中水援,是指一個時間段中有幾個程序都處于已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行茅郎。
就想前面提到的操作系統(tǒng)的時間片分時調度蜗元。打游戲和聽音樂兩件事情在同一個時間段內都是在同一臺電腦上完成了從開始到結束的動作。那么系冗,就可以說聽音樂和打游戲是并發(fā)的奕扣。
-
并行:
并行(Parallel),當系統(tǒng)有一個以上CPU時掌敬,當一個CPU執(zhí)行一個進程時惯豆,另一個CPU可以執(zhí)行另一個進程,兩個進程互不搶占CPU資源奔害,可以同時進行楷兽,這種方式我們稱之為并行(Parallel)。
這里面有一個很重要的點华临,那就是系統(tǒng)要有多個CPU才會出現(xiàn)并行芯杀。在有多個CPU的情況下,才會出現(xiàn)真正意義上的『同時進行』。
什么是僵尸進程瘪匿?
答:僵尸進程是當子進程比父進程先結束,而父進程又沒有回收子進程寻馏,釋放子進程占用的資源棋弥,此時子進程將成為一個僵尸進程。如果父進程先退出诚欠,子進程被init接管顽染,子進程推出后init會回收其占用的相關資源。如果太多僵尸進程的話轰绵,會導致系統(tǒng)的進程號不夠用粉寞,不再產(chǎn)生進程。解決方法: (1) 讓僵尸進程成為孤兒進程左腔,由init進程回收唧垦;(手動殺死父進程)。(2) 父進程用wait或waitpid去回收資源(方案不好)父進程通過wait或waitpid等函數(shù)去等待子進程結束液样,但是不好振亮,會導致父進程一直等待被掛起,相當于一個進程在干活鞭莽,沒有起到多進程的作用坊秸。
線程死鎖是如何產(chǎn)生的,如何避免 澎怒?
答:
- 線程死鎖的條件:
- 互斥條件:一個資源在同一時刻只由一個線程占用褒搔。
- 請求與保持條件:一個線程在請求被占資源時發(fā)生阻塞,并對已獲得的資源保持不放喷面。
- 循環(huán)等待條件:發(fā)生死鎖時星瘾,所有的線程會形成一個死循環(huán),一直阻塞乖酬。
- 不剝奪條件:線程已獲得的資源在未使用完不能被其他線程剝奪死相,只能由自己使用完釋放資源。
- 避免死鎖的方法:只有上面四個條件達成才能形成死鎖咬像,所以我們只需要破壞上面任意一個條件即可
- 破壞互斥條件:使資源同時訪問而非互斥使用算撮,就沒有進程會阻塞在資源上,從而不發(fā)生死鎖县昂。但是這種場景很少肮柜,因為你資源共享的話,如果是只讀就可以倒彰,但是設計到修改很可能會導致異常审洞。而且我們加鎖就是為了互斥。
- 破壞占有和等待條件:采用靜態(tài)分配的方式,靜態(tài)分配的方式是指進程必須在執(zhí)行之前就申請需要的全部資源芒澜,且直至所要的資源全部得到滿足后才開始執(zhí)行仰剿。
- 占有部分資源的線程進一步申請其他資源時,如果申請不到痴晦,主動釋放它占有的資源南吮,破壞 "不可搶占" 條件
- 按序申請資源,破壞 "循環(huán)等待" 條件
io多路復用誊酌,介紹select,poll,epoll原理部凑,他們的優(yōu)缺點及不同?
手寫死鎖碧浊?
Lock lock1 = new ReentrantLock();
Lock lock2 = new ReentrantLock();
static Runnable a = () -> {
try {
while (true) {
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
// lock1.lock();
synchronized (test.obj1) {
System.out.println("Thread 1 lock 1");
Thread.sleep(5000);
// lock2.lock();
synchronized (test.obj2) {
System.out.println("Thread 1 lock 2");
Thread.sleep(5000);
}
// lock2.unlock();
System.out.println("Thread 1 unlock 2");
// lock1.unlock();
}
System.out.println("Thread 1 unlock 1");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
};
static Thread thread1 = new Thread(a);
static Thread thread2 = new Thread(() -> {
try {
while (true) {
// lock2.lock();
synchronized (test.obj2) {
System.out.println("Thread 2 lock 2");
Thread.sleep(5000);
// lock1.lock();
synchronized (test.obj1) {
System.out.println("Thread 2 lock 1");
Thread.sleep(5000);
}
// lock1.unlock();
System.out.println("Thread 2 unlock 1");
// lock2.unlock();
}
System.out.println("Thread 2 unlock 2");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
public static String obj1 = "obj1";
public static String obj2 = "obj2";
public static void main(String[] args) {
thread1.start();
thread2.start();
}
簡述操作系統(tǒng)如何進行內存管理?
答:
-
為什么要內存管理涂邀?
答:早期,程序直接運行在物理內存上箱锐,直接操作物理內存比勉,這種方式存在幾個問題:
1、地址空間不隔離:程序操作相同地址空間會造成互相影響甚至崩潰瑞躺,而且安全性也得不到保證敷搪;2、使用效率低:沒有特別好的策略保證多個進程對超過物理內存大小的內存需求的滿足幢哨;3赡勘、程序運行地址不確定:程序運行時,都需要分配空閑區(qū)域捞镰,而空閑位置不確定闸与,會帶來一些重定位問題; -
虛擬內存
計算機系統(tǒng)里任何問題都可以靠引入一個中間層來解決岸售,內存管理就在程序和物理內存之間引入了虛擬內存的概念践樱;對進程地址和物理地址進行隔離;
簡述操作系統(tǒng)中的缺頁中斷?
答:
- 概念: malloc()和mmap()等內存分配函數(shù)凸丸,在分配時只是建立了進程虛擬地址空間拷邢,并沒有分配虛擬內存對應的物理內存。當進程訪問這些沒有建立映射關系的虛擬內存時屎慢,處理器自動觸發(fā)一個缺頁異常瞭稼。
- 缺頁中斷:在請求分頁系統(tǒng)中,可以通過查詢頁表中的狀態(tài)位來確定所要訪問的頁面是否存在于內存中腻惠。每當所要訪問的頁面不在內存是环肘,會產(chǎn)生一次缺頁中斷,此時操作系統(tǒng)會根據(jù)頁表中的外存地址在外存中找到所缺的一頁集灌,將其調入內存悔雹。
什么時候會由用戶態(tài)陷入內核態(tài)?
答:
-
為何要區(qū)分用戶態(tài)和內核態(tài)?
最簡單的運行程序的方式是“直接執(zhí)行”腌零,即直接在 CPU 上執(zhí)行任意程序梯找。直接執(zhí)行的問題是:1、如何限制代碼行為益涧?比如禁止:設置特殊寄存器的值初肉、訪問存儲器的任意位置、I/O 請求饰躲、申請更多系統(tǒng)資源等。2臼隔、在運行這個程序的時候嘹裂,如何切換到另一個程序?進程調度應該是 OS 才有的權限摔握。因此引入用戶態(tài)和內核態(tài)和兩種模式寄狼。用戶態(tài)無法執(zhí)行受限操作,如 I/O 請求氨淌,執(zhí)行這些操作會引發(fā)異常泊愧。核心態(tài)只能由操作系統(tǒng)運行,可以執(zhí)行特權操作盛正。用戶程序通過系統(tǒng)調用 system call 執(zhí)行這些特權操作删咱。OS 執(zhí)行前會判斷進程是否有權限執(zhí)行相應的指令。區(qū)分用戶態(tài)和核心態(tài)的執(zhí)行機制稱為“受限直接執(zhí)行”(Limited Direct Execution)豪筝。 - 什么時候會陷入內核態(tài)痰滋?
系統(tǒng)調用(trap)、中斷(interrupt)和異常(exception)续崖。
系統(tǒng)調用是用戶進程主動發(fā)起的操作敲街。發(fā)起系統(tǒng)調用,陷入內核严望,由操作系統(tǒng)執(zhí)行系統(tǒng)調用多艇,然后再返回到進程。
中斷和異常是被動的像吻,無法預測發(fā)生時機峻黍。中斷包括 I/O 中斷、外部信號中斷萧豆、各種定時器引起的時鐘中斷等奸披。異常包括程序運算引起的各種錯誤如除 0、緩沖區(qū)溢出涮雷、缺頁等阵面。
在系統(tǒng)的處理上,中斷和異常類似,都是通過中斷向量表來找到相應的處理程序進行處理样刷。區(qū)別在于仑扑,中斷來自處理器外部,不是由任何一條專門的指令造成置鼻,而異常是執(zhí)行當前指令的結果镇饮。
操作系統(tǒng)中,虛擬地址與物理地址之間如何映射箕母?
Linux 下如何查看端口被哪個進程占用储藐?
答:lsof -i:端口號
進程通信中的管道實現(xiàn)原理是什么?
答:
管道是如何通信的:
管道是由內核管理的一個緩沖區(qū)嘶是,相當于我們放入內存中的一個紙條钙勃。管道的一端連接一個進程的輸出。這個進程會向管道中放入信息聂喇。管道的另一端連接一個進程的輸入辖源,這個進程取出被放入管道的信息。一個緩沖區(qū)不需要很大希太,它被設計成為環(huán)形的數(shù)據(jù)結構克饶,以便管道可以被循環(huán)利用。當管道中沒有信息的話誊辉,從管道中讀取的進程會等待矾湃,直到另一端的進程放入信息。當管道被放滿信息的時候堕澄,嘗試放入信息的進程會等待洲尊,直到另一端的進程取出信息。當兩個進程都終結的時候奈偏,管道也自動消失坞嘀。管道是如何創(chuàng)建的:
從原理上,管道利用fork機制建立惊来,從而讓兩個進程可以連接到同一個PIPE上丽涩。最開始的時候,上面的兩個箭頭都連接在同一個進程Process 1上(連接在Process 1上的兩個箭頭)裁蚁。當fork復制進程的時候矢渊,會將這兩個連接也復制到新的進程(Process 2)。隨后枉证,每個進程關閉自己不需要的一個連接 (兩個黑色的箭頭被關閉; Process 1關閉從PIPE來的輸入連接矮男,Process 2關閉輸出到PIPE的連接),這樣室谚,剩下的紅色連接就構成了如上圖的PIPE毡鉴。-
管道通信的實現(xiàn)細節(jié):
在 Linux 中崔泵,管道的實現(xiàn)并沒有使用專門的數(shù)據(jù)結構,而是借助了文件系統(tǒng)的file結構和VFS的索引節(jié)點inode猪瞬。通過將兩個 file 結構指向同一個臨時的 VFS 索引節(jié)點憎瘸,而這個 VFS 索引節(jié)點又指向一個物理頁面而實現(xiàn)的。如下圖
例子
有兩個 file 數(shù)據(jù)結構陈瘦,但它們定義文件操作例程地址是不同的幌甘,其中一個是向管道中寫入數(shù)據(jù)的例程地址,而另一個是從管道中讀出數(shù)據(jù)的例程地址痊项。這樣锅风,用戶程序的系統(tǒng)調用仍然是通常的文件操作,而內核卻利用這種抽象機制實現(xiàn)了管道這一特殊操作鞍泉。
Linux 下如何排查 CPU 以及 內存占用過多遏弱?
答:CPU的話使用TOP命令去查一下哪些線程
簡述 Linux 虛擬內存的頁面置換算法?
簡述 Linux 零拷貝的原理?
答:
參考文章