一、linux和os:
netstat :顯示網絡狀態
tcpdump:主要是截獲通過本機網絡接口的數據,用以分析。能夠截獲當前所有通過本機網卡的數據包。它擁有靈活的過濾機制,可以確保得到想要的數據。
ipcs:檢查系統上共享內存的分配
ipcrm:手動解除系統上共享內存的分配
(如果這四個命令沒聽說過或者不能熟練使用,基本上可以回家,通過的概率較小 ^_^ ,這四個命令的熟練掌握程度基本上能體現面試者實際開發和調試程序的經驗)
cpu 內存 硬盤 等等與系統性能調試相關的命令必須熟練掌握,設置修改權限 tcp網絡狀態查看 各進程狀態 抓包相關等相關命令 必須熟練掌握
awk sed需掌握
1. 共享內存的使用實現原理
(必考必問,然后共享內存段被映射進進程空間之后,存在于進程空間的什么位置?共享內存段最大限制是多少?)
共享內存定義:共享內存是最快的可用IPC(進程間通信)形式。它允許多個不相關的進程去訪問同一部分邏輯內存。共享內存是由IPC為一個進程創建的一個特殊的地址范圍,它將出現在進程的地址空間中。其他進程可以把同一段共享內存段“連接到”它們自己的地址空間里去。所有進程都可以訪問共享內存中的地址。如果一個進程向這段共享內存寫了數據,所做的改動會立刻被有訪問同一段共享內存的其他進程看到。因此共享內存對于數據的傳輸是非常高效的。
共享內存的原理:共享內存是最有用的進程間通信方式之一,也是最快的IPC形式。兩個不同進程A、B共享內存的意思是,同一塊物理內存被映射到進程A、B各自的進程地址空間。進程A可以即時看到進程B對共享內存中數據的更新,反之亦然。
2. c++進程內存空間分布(注意各部分的內存地址誰高誰低,注意棧從高到低分配,堆從低到高分配)
3. 使用過哪些進程間通訊機制,并詳細說明(重點)
4. makefile編寫,雖然比較基礎,但是會被問到
5. gdb調試相關的經驗,會被問到
6. 如何定位內存泄露?
內存泄漏是指堆內存的泄漏。堆內存是指程序從堆中分配的、大小任意的(內存塊的大小可以在程序運行期決定)、使用完后必須顯示釋放的內存。應用程序一般使用malloc、realloc、new等函數從堆中分配到一塊內存,使用完后,程序必須負責相應的調用free或delete釋放該內存塊。否則,這塊內存就不能被再次使用,我們就說這塊內存泄漏了。
C++程序缺乏相應的手段來檢測內存信息,只能使用top指令觀察進程的動態內存總額。而且程序退出時,我們無法獲知任何內存泄漏信息
使用Linux命令回收內存,可以使用ps、kill兩個命令檢測內存使用情況和進行回收。在使用超級用戶權限時使用命令“ps”,它會列出所有正在運行的程序名稱和對應的進程號(PID)。kill命令的工作原理是向Linux操作系統的內核送出一個系統操作信號和程序的進程號(PID)
7. 動態鏈接和靜態鏈接的區別
動態鏈接是指在生成可執行文件時不將所有程序用到的函數鏈接到一個文件,因為有許多函數在操作系統帶的dll文件中,當程序運行時直接從操作系統中找。 而靜態鏈接就是把所有用到的函數全部鏈接到exe文件中。
動態鏈接是只建立一個引用的接口,而真正的代碼和數據存放在另外的可執行模塊中,在運行時再裝入;而靜態鏈接是把所有的代碼和數據都復制到本模塊中,運行時就不再需要庫了。
8. 32位系統一個進程最多有多少堆內存
9. 多線程和多進程的區別
重點 面試官最最關心的一個問題,必須從cpu調度,上下文切換,數據共享,多核cup利用率,資源占用,等等各方面回答,然后有一個問題必須會被問到:哪些東西是一個線程私有的?答案中必須包含寄存器,否則悲催
10. 說出你所知道的linux系統的各類同步機制(重點)
11. 什么是死鎖?如何避免死鎖(每個技術面試官必問)
12. 死鎖的條件
(互斥條件(Mutual exclusion):
1、資源不能被共享,只能由一個進程使用。
2、請求與保持條件(Hold and wait):已經得到資源的進程可以再次申請新的資源。
3、非剝奪條件(No pre-emption):已經分配的資源不能從相應的進程中被強制地剝奪。
4、循環等待條件(Circular wait):系統中若干進程組成環路,該環路中每個進程都在等待相鄰進程正占用的資源。
13. 處理死鎖的策略:
忽略該問題。例如鴕鳥算法,該算法可以應用在極少發生死鎖的的情況下。為什么叫鴕鳥算法呢,因為傳說中鴕鳥看到危險就把頭埋在地底下,可能鴕鳥覺得看不到危險也就沒危險了吧。跟掩耳盜鈴有點像。
檢測死鎖并且恢復。
仔細地對資源進行動態分配,以避免死鎖。
通過破除死鎖四個必要條件之一,來防止死鎖產生。)
14. 列舉說明linux系統的各類異步機制
15. exit()與_exit()的區別?
_exit終止調用進程,但不關閉文件,不清除輸出緩存,也不調用出口函數。exit函數將終止調用進程。在退出程序之前,所有文件關閉,緩沖輸出內容將刷新定義,并調用所有已刷新的“出口函數”(由atexit定義)。
‘exit()’與‘_exit()’有不少區別在使用‘fork()’,特別是‘vfork()’時變得很突出。
‘exit()’與‘_exit()’的基本區別在于前一個調用實施與調用庫里用戶狀態結構(user-mode constructs)有關的清除工作(clean-up),而且調用用戶自定義的清除程序
16. linux的內存管理機制是什么?
Linux虛擬內存的實現需要6種機制的支持:地址映射機制、內存分配回收機制、緩存和刷新機制、請求頁機制、交換機制和內存共享機制
內存管理程序通過映射機制把用戶程序的邏輯地址映射到物理地址。當用戶程序運行時,如果發現程序中要用的虛地址沒有對應的物理內存,就發出了請求頁要求。如果有空閑的內存可供分配,就請求分配內存(于是用到了內存的分配和回收),并把正在使用的物理頁記錄在緩存中(使用了緩存機制)。如果沒有足夠的內存可供分配,那么就調用交換機制;騰出一部分內存。另外,在地址映射中要通過TLB(翻譯后援存儲器)來尋找物理頁;交換機制中也要用到交換緩存,并且把物理頁內容交換到交換文件中,也要修改頁表來映射文件地址。
17. linux的任務調度機制是什么?
18. 標準庫函數和系統調用的區別?
19. 系統如何將一個信號通知到進程
二、C語言:
宏定義和展開(必須精通)
位操作(必須精通)
指針操作和計算(必須精通)
內存分配(必須精通)
sizeof必考
各類庫函數必須非常熟練的實現
哪些庫函數屬于高危函數,為什么?(strcpy等等)
三、c++:
1. 一個String類的完整實現必須很快速寫出來(注意:賦值構造,operator=是關鍵)
2. 虛函數的作用和實現原理(必問必考,實現原理必須很熟)
有虛函數的類內部有一個稱為“虛表”的指針(有多少個虛函數就有多少個指針),這個就是用來指向這個類虛函數。也就是用它來確定調用該那個函數。
實際上在編譯的時候,編譯器會自動加入“虛表”。虛表的使用方法是這樣的:如果派生類在自己的定義中沒有修改基類的虛函數,就指向基類的虛函數;如果派生類改寫了基類的虛函數(就是自己重新定義),這時虛表則將原來指向基類的虛函數的地址替換為指向自身虛函數的指針。那些被virtual關鍵字修飾的成員函數,就是虛函數。虛函數的作用,用專業術語來解釋就是實現多態性(Polymorphism),多態性是將接口與實現進行分離;用形象的語言來解釋就是實現以共同的方法,但因個體差異而采用不同的策略。
每個類都有自己的vtbl,vtbl的作用就是保存自己類中虛函數的地址,我們可以把vtbl形象地看成一個數組,這個數組的每個元素存放的就是虛函數的地址,
虛函數的效率低,其原因就是,在調用虛函數之前,還調用了獲得虛函數地址的代碼。
3. sizeof一個類求大小(注意成員變量,函數,虛函數,繼承等等對大小的影響)
4. 指針和引用的區別(一般都會問到)
指針指向一塊內存,它的內容是所指內存的地址;而引用是某塊內存的別名。
相同點: 都是地址的概念;
區別:
指針是一個實體,而引用僅是個別名;
引用使用時無需解引用(*),指針需要解引用;
引用只能在定義時被初始化一次,之后不可變;指針可變;
引用沒有 const,指針有 const;
引用不能為空,指針可以為空;
“sizeof 引用”得到的是所指向的變量(對象)的大小,而“sizeof 指針”得到的是指針本身(所指向的變量或對象的地址)的大小;
指針和引用的自增(++)運算意義不一樣;
從內存分配上看:程序為指針變量分配內存區域,而引用不需要分配內存區域。
5. 多重類構造和析構的順序
先調用基類的構造函數,在調用派生類的構造函數
先構造的后析構,后構造的先析構
6. stl各容器的實現原理(必考)
STL共有六大組件
1、容器。2、算法。3、迭代器。4、仿函數。6、適配器。
序列式容器:
vector-數組,元素不夠時再重新分配內存,拷貝原來數組的元素到新分配的數組中。
list-單鏈表。
deque-分配中央控制器map(并非map容器),map記錄著一系列的固定長度的數組的地址.記住這個map僅僅保存的是數組的地址,真正的數據在數組中存放著.deque先從map中央的位置(因為雙向隊列,前后都可以插入元素)找到一個數組地址,向該數組中放入數據,數組不夠時繼續在map中找空閑的數組來存數據。當map也不夠時重新分配內存當作新的map,把原來map中的內容copy的新map中。所以使用deque的復雜度要大于vector,盡量使用vector。
stack-基于deque。
queue-基于deque。
heap-完全二叉樹,使用最大堆排序,以數組(vector)的形式存放。
priority_queue-基于heap。
slist-雙向鏈表。
關聯式容器:
set,map,multiset,multimap-基于紅黑樹(RB-tree),一種加上了額外平衡條件的二叉搜索樹。
hash table-散列表。將待存數據的key經過映射函數變成一個數組(一般是vector)的索引,例如:數據的key%數組的大小=數組的索引(一般文本通過算法也可以轉換為數字),然后將數據當作此索引的數組元素。有些數據的key經過算法的轉換可能是同一個數組的索引值(碰撞問題,可以用線性探測,二次探測來解決),STL是用開鏈的方法來解決的,每一個數組的元素維護一個list,他把相同索引值的數據存入一個list,這樣當list比較短時執行刪除,插入,搜索等算法比較快。
hash_map,hash_set,hash_multiset,hash_multimap-基于hash table。
7. extern c 是干啥的,(必須將編譯器的函數名修飾的機制解答的很透徹)
8. volatile是干啥用的,(必須將cpu的寄存器緩存機制回答的很透徹)
volatile的本意是“易變的” 因為訪問寄存器要比訪問內存單元快的多,所以編譯器一般都會作減少存取內存的優化,但有可能會讀臟數據。當要求使用volatile聲明變量值的時候,系統總是重新從它所在的內存讀取數據,即使它前面的指令剛剛從該處讀取過數據。精確地說就是,遇到這個關鍵字聲明的變量,編譯器對訪問該變量的代碼就不再進行優化,從而可以提供對特殊地址的穩定訪問;如果不使用volatile,則編譯器將對所聲明的語句進行優化。(簡潔的說就是:volatile關鍵詞影響編譯器編譯的結果,用volatile聲明的變量表示該變量隨時可能發生變化,與該變量有關的運算,不要進行編譯優化,以免出錯)
volatile的本質:
編譯器的優化
在本次線程內, 當讀取一個變量時,為提高存取速度,編譯器優化時有時會先把變量讀取到一個寄存器中;以后,再取變量值時,就直接從寄存器中取值;當變量值在本線程里改變時,會同時把變量的新值copy到該寄存器中,以便保持一致。
當變量在因別的線程等而改變了值,該寄存器的值不會相應改變,從而造成應用程序讀取的值和實際的變量值不一致。
當該寄存器在因別的線程等而改變了值,原變量的值不會改變,從而造成應用程序讀取的值和實際的變量值不一致。
volatile應該解釋為“直接存取原始內存地址”比較合適,“易變的”這種解釋簡直有點誤導人。
9. static const等等的用法,(能說出越多越好)
四、數據結構或者算法:
各類樹結構的實現和應用
各類排序:大根堆的實現,快排(如何避免最糟糕的狀態?),bitmap的運用等等
hash, 任何一個技術面試官必問(例如為什么一般hashtable的桶數會取一個素數?如何有效避免hash結果值的碰撞)
五、網絡編程:
1. tcp與udp的區別(必問)
基于連接與無連接
對系統資源的要求(TCP較多,UDP少)
UDP程序結構較簡單
流模式與數據報模式
TCP保證數據正確性,UDP可能丟包,TCP保證數據順序,UDP不保證
TCP—傳輸控制協議,提供的是面向連接、可靠的字節流服務。當客戶和服務器彼此交換數據前,必須先在雙方之間建立一個TCP連接,之后才能傳輸數據。TCP提供超時重發,丟棄重復數據,檢驗數據,流量控制等功能,保證數據能從一端傳到另一端。
UDP—用戶數據報協議,是一個簡單的面向數據報的運輸層協議。UDP不提供可靠性,它只是把應用程序傳給IP層的數據報發送出去,但是并不能保證它們能到達目的地。由于UDP在傳輸數據報前不用在客戶和服務器之間建立一個連接,且沒有超時重發等機制,故而傳輸速度很快
2. socket服務端的實現,select和epoll的區別(必問)
select的本質是采用32個整數的32位,即32*32= 1024來標識,fd值為1-1024。當fd的值超過1024限制時,就必須修改FD_SETSIZE的大小。這個時候就可以標識32*max值范圍的fd。
對于單進程多線程,每個線程處理多個fd的情況,select是不適合的。
1.所有的線程均是從1-32*max進行掃描,每個線程處理的均是一段fd值,這樣做有點浪費
2.1024上限問題,一個處理多個用戶的進程,fd值遠遠大于1024
所以這個時候應該采用poll,
poll傳遞的是數組頭指針和該數組的長度,只要數組的長度不是很長,性能還是很不錯的,因為poll一次在內核中申請4K(一個頁的大小來存放fd),盡量控制在4K以內
epoll還是poll的一種優化,返回后不需要對所有的fd進行遍歷,在內核中維持了fd的列表。select和poll是將這個內核列表維持在用戶態,然后傳遞到內核中。但是只有在2.6的內核才支持。
epoll更適合于處理大量的fd ,且活躍fd不是很多的情況,畢竟fd較多還是一個串行的操作
epoll哪些觸發模式,有啥區別?(必須非常詳盡的解釋水平觸發和邊緣觸發的區別,以及邊緣觸發在編程中要做哪些更多的確認)
epoll可以同時支持水平觸發和邊緣觸發(Edge Triggered,只告訴進程哪些文件描述符剛剛變為就緒狀態,它只說一遍,如果我們沒有采取行動,那么它將不會再次告知,這種方式稱為邊緣觸發),理論上邊緣觸發的性能要更高一些,但是代碼實現相當復雜。
epoll同樣只告知那些就緒的文件描述符,而且當我們調用epoll_wait()獲得就緒文件描述符時,返回的不是實際的描述符,而是一個代表就緒描述符數量的值,你只需要去epoll指定的一個數組中依次取得相應數量的文件描述符即可,這里也使用了內存映射(mmap)技術,這樣便徹底省掉了這些文件描述符在系統調用時復制的開銷。
另一個本質的改進在于epoll采用基于事件的就緒通知方式。在select/poll中,進程只有在調用一定的方法后,內核才對所有監視的文件描述符進行掃描,而epoll事先通過epoll_ctl()來注冊一個文件描述符,一旦基于某個文件描述符就緒時,內核會采用類似callback的回調機制,迅速激活這個文件描述符,當進程調用epoll_wait()時便得到通知。
3. 大規模連接上來,并發模型怎么設計
4. tcp結束連接怎么握手,time_wait狀態是什么,為什么會有time_wait狀態?哪一方會有time_wait狀態,如何避免time_wait狀態占用資源(必須回答的詳細)
5. tcp頭多少字節?哪些字段?(必問)
頭20字節,選項12字節
6. connect會阻塞,怎么解決?(必考必問)
最通常的方法最有效的是加定時器;也可以采用非阻塞模式。
設置非阻塞,返回之后用select檢測狀態)
如果select返回可讀,結果只讀到0字節,什么情況?
某個套接字集合中沒有準備好,可能會select內存用FD_CLR清該位為0;