【面試】網易遊戲社招一面總結

基本情況

面試崗位:Python遊戲開發崗
面試方式:視頻面試
面試官數量:2人
面試感覺:首先,開場之後,無需自我介紹,從簡歷開始問,這一點很有技術範兒。面試過程中,兩位面試官交叉提問,並且在回答過程中根據技術點隨時打斷補充提問,很像是一個開發小組在就有個問題討論。另外在回答問題過程中,可能有些問題回答不上來,面試官還能夠給與一點提示,這一點感覺非常好。最後,雖然自己水平很差,但是能夠有這樣的交流,收穫滿滿,也非常感謝兩位年輕帥氣的面試官。

問題列表

Java部分

  1. 在公司做了哪些項目?主要用到的哪些技術?自己的貢獻是什麼?
    答:結合實際情況回答,例如,Spring,SpringBoot,MyBatis,Redis, MySQL,Zabbix,Ubuntu等

  2. 使用的應用服務器是什麼?它的啓動流程,它是如何根據URL找到對應的處理邏輯?
    答:使用的是jetty。外部啓動一個Jetty服務器的流程如下:
    1)java start.jar進行啓動,解析命令行參數並讀取start.ini中配置的所有參數;
    2)解析start.config確定jetty模塊的類路徑並確定首先執行的MainClass;
    3)可以選擇是否另起一個進程來,如果不另起進程,則通過反射來調用MainClass,start.ini中配置的JVM參數不會生效;
    4)MainClass默認是XmlConfiguration,解析etc/jetty.xml,etc/jetty-deploy.xml等,創建實例並組裝Server(是根據在start.ini中定義的順序創建,而且順序很重要,這裏的IOC是jetty自己實現的),然後調用start()啓動Server()。
    5)Server啓動其他組件的順序是:首先啓動設置到Server的Handler,通常這個Handler會有很多子handler,這些handler將組成一個Handler鏈,Server會依次啓動這個鏈上的所有Handler,接着會啓動註冊在Server上JMX的Mbean,讓Mbean也一起工作,最後會啓動Connector,打開端口,接受客戶端請求。

補充知識:Jetty處理請求流程
Jetty接收到一個請求時,Jetty就把這個請求交給在Server中註冊的而代理Handler去執行,如何執行註冊的Handler同樣由你規定,Jetty要做的就是調用你註冊的第一個Handler的handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)方法,接下來要怎麼做,完全由你決定。要能接收一個Web請求訪問,首先要創建一個ContextHandler
當我們在瀏覽器中輸http://localhost:8080時請求將會代理到Server類的handle方法,Server的handle方法將請求代理給ContextHandler的handle方法,ContextHandler又調用另一個Handler的handle方法。這個調用方式是和Servlet的工作方式類似,在啓動之前初始化,創建對象後調用Servlet的service方法。在Servlet的API中我通常也只實現它的一個包裝好的類,在Jetty中也是如此。雖然ContextHandler也只是一個handler,但是這個Handler通常由Jetty幫你實現,我們一般只要實現一些與具體要做的業務邏輯有關的Handler就好了,而一些流程性的或某些規範的Handler,我們直接用就好了。下圖是請求Servlet的時序圖。
Jetty處理流程圖Jetty處理請求的過程就是Handler鏈上handle方法的執行過程。這裏需要解釋的一點是ScopeHandler的處理規則,ServletContextHandler、SessionHandler和ServletHandler都繼承了ScopeHandler,那麼這三個類組成一個Handler鏈,他們的執行規則是ServletContextHandler.handler→ServletContextHandler.doScope→SessionHandler.doScope→ServletHandler.doScope→ServletContextHandler.doHandle→SessionHandler.doHandle→ServletHandler.doHandle,這種機制使得我們可以在duScope階段做一些額外工作。

補充問題:Jetty和Tomcat的比較

  • 相同點:Tomcat和Jetty都是一種Servlet引擎,他們都支持標準的servlet規範和JavaEE的規範。
  • 不同點:
    • 架構比較
      • Jetty的架構比Tomcat的更爲簡單
      • Jetty的架構是基於Handler來實現的,主要的擴展功能都可以用Handler來實現,擴展簡單。
      • Tomcat的架構是基於容器設計的,進行擴展是需要了解Tomcat的整體設計結構,不易擴展。
    • 性能比較
      • Jetty和Tomcat性能方面差異不大
      • Jetty可以同時處理大量連接而且可以長時間保持連接,適合於web聊天應用等等。
      • Jetty的架構簡單,因此作爲服務器,Jetty可以按需加載組件,減少不需要的組件,減少了服務器內存開銷,從而提高服務器性能。
      • Jetty默認採用NIO結束在處理I/O請求上更佔優勢,在處理靜態資源時,性能較高
      • 少數非常繁忙;Tomcat適合處理少數非常繁忙的鏈接,也就是說鏈接生命週期短的話,Tomcat的總體性能更高。Tomcat默認採用BIO處理I/O請求,在處理靜態資源時,性能較差。
    • 其它比較
      • Jetty的應用更加快速,修改簡單,對新的Servlet規範的支持較好。
      • Tomcat目前應用比較廣泛,對JavaEE和Servlet的支持更加全面,很多特性會直接集成進來。
  1. 在Spring框架中web.xml的結構是什麼?
    答:1)Spring框架解決字符串編碼問題:過濾器 CharacterEncodingFilter(filter-name), 過濾器就是針對於每次瀏覽器請求進行過濾的
    2)在web.xml配置監聽器ContextLoaderListener(listener-class),ContextLoaderListener的作用就是啓動Web容器時,自動裝配ApplicationContext的配置信息。因爲它實現了ServletContextListener這個接口,在web.xml配置這個監聽器,啓動容器時,就會默認執行它實現的方法。 在ContextLoaderListener中關聯了ContextLoader這個類,所以整個加載配置過程由ContextLoader來完成。
    3)部署applicationContext的xml文件:contextConfigLocation(context-param下的param-name)
    4)DispatcherServlet是前置控制器,配置在web.xml文件中的。攔截匹配的請求,Servlet攔截匹配規則要自已定義,把攔截下來的請求,依據某某規則分發到目標Controller來處理。
    5)DispatcherServlet(servlet-name、servlet-class、init-param、param-name(contextConfigLocation)、param-value) ,在DispatcherServlet的初始化過程中,框架會在web應用的 WEB-INF文件夾下尋找名爲[servlet-name]-servlet.xml 的配置文件,生成文件中定義的bean。

  2. Java的集合類中List有哪幾種實現?Arralist與Vector區別?Arraylist與LinkedList區別?以及它們的擴增方式。
    答:常見的實現有三種:ArrayList,LinkedList,Vector。另外還有AbstractList,AbstractSequentialList等。它們之間的區別如下:
    ArrayList:
    1)ArrayList底層通過數組實現,隨着元素的增加而動態擴容。
    2)ArrayList是Java集合框架中使用最多的一個類,是一個數組隊列,線程不安全集合。
    3)它繼承於AbstractList,實現了List, RandomAccess, Cloneable, Serializable接口。①ArrayList實現List,得到了List集合框架基礎功能;②ArrayList實現RandomAccess,獲得了快速隨機訪問存儲元素的功能,RandomAccess是一個標記接口,沒有任何方法;③ArrayList實現Cloneable,得到了clone()方法,可以實現克隆功能;④ArrayList實現Serializable,表示可以被序列化,通過序列化去傳輸,典型的應用就是hessian協議。
    4)ArrayList的特點:容量不固定,隨着容量的增加而動態擴容(閾值基本不會達到);有序集合(插入的順序==輸出的順序);插入的元素可以爲null;增刪改查效率更高(相對於LinkedList來說);線程不安全
    ArrayList擴增源碼如下:
    ArrayList擴增源碼
    LinkedList
    1)LinkedList底層通過鏈表來實現,隨着元素的增加不斷向鏈表的後端增加節點。
    2)LinkedList是一個雙向鏈表,每一個節點都擁有指向前後節點的引用。相比於ArrayList來說,LinkedList的隨機訪問效率更低。
    3)它繼承AbstractSequentialList,實現了List, Deque, Cloneable, Serializable接口。①LinkedList實現List,得到了List集合框架基礎功能;②LinkedList實現Deque,Deque 是一個雙向隊列,也就是既可以先入先出,又可以先入後出,說簡單點就是既可以在頭部添加元素,也可以在尾部添加元素;③LinkedList實現Cloneable,得到了clone()方法,可以實現克隆功能;④LinkedList實現Serializable,表示可以被序列化,通過序列化去傳輸,典型的應用就是hessian協議。
    Vector
    和ArrayList基本相似,利用數組及擴容實現List,但Vector是一種線程安全的List結構,它的讀寫效率不如ArrayList,其原因是在該實現類內在方法上加上了同步關鍵字。源碼如下:
    Vector獲取元素
    其不同之處還在於Vector的增長速度不同:即
    Vector增加元素
    Vector擴增
    Vector在默認情況下是以兩倍速度遞增,所以capacityIncrement可以用來設置遞增速度,因此Vector的初始化多了一種方式,即設置數組增量。
    Arralist與Vector區別與聯繫
    1) ArrayList出現於jdk1.2,Vector出現於1.0。兩者底層的數據存儲都使用的Object數組實現,因爲是數組實現,所以具有查找快(因爲數組的每個元素的首地址是可以得到的,數組是0序的,所以: 被訪問元素的首地址=首地址+元素類型字節數*下標 ),增刪慢(因爲往數組中間增刪元素時,會導致後面所有元素地址的改變)的特點
    2)繼承的類實現的接口都是一樣的,都繼承了AbstractList類(繼承後可以使用迭代器遍歷),實現了RandomAccess(標記接口,標明實現該接口的list支持快速隨機訪問),cloneable接口(標識接口,合法調用clone方法),serializable(序列化標識接口)
    3)當兩者容量不夠時,都會進行對Object數組的擴容,arraylist默認增長1.5倍;Vector可以自定義若不自定義,則增長2倍
    4)構造方法略有不同
    ①ArrayList的構造方法:
    ArrayList a1 = new ArrayList(int i); 指定初始化容量的構造方法
    ArrayList a2 = new ArrayList(); 默認構造方法,在添加第一個元素過程中初始化一個長度爲10的Object數組
    ArrayList a3 = new ArrayList(Collection); 在構造方法中添加集合,本方法創建的集合的object數組長度等於實際元素個數
    ②Vector的構造方法:
    Vector v1 = new Vector(10,2); 指定初始長度(initialCapacity)與增長因子(capacityIncrement)注意這裏的增長因子不是oldCapacity * capacityIncrement而是+,如果不指定或者指定爲0,則默認擴容當前容量的兩倍。
    Vector v2 = new Vector(10); 通過this關鍵字調用上面的構造方法,自定義初始數組長度,增長因子默認爲0
    Vector v3 = new Vector(); 默認構造方法,在創建對象時便分配長度爲10的Object數組
    5)線程的安全性不同,Vector是線程安全的,在Vector的大多數方法都使用synchronized關鍵字修飾,ArrayList是線程不安全的(可以通過Collections.synchronizedList()實現線程安全)
    6)性能上的差別,由於Vector的方法都有同步鎖,在方法執行時需要加鎖、解鎖,所以在執行過程中效率會低於ArrayList,另外,性能上的差別還體現在底層的Object數組上,ArrayList多了一個transient關鍵字,這個關鍵字的作用是防止序列化,然後在ArrayList中重寫了readObject和writeObject方法,這樣是爲了在傳輸時提高效率。
    ArrayList和LinkedList比較
    1)對ArrayList和LinkedList而言,在列表末尾增加一個元素所花的開銷都是固定的。對ArrayList而言,主要是在內部數組中增加一項,指向所添加的元素,偶爾可能會導致對數組重新進行分配;而對LinkedList而言,這個開銷是統一的,分配一個內部Entry對象。
    2)在ArrayList的中間插入或刪除一個元素意味着這個列表中剩餘的元素都會被移動;而在LinkedList的中間插入或刪除一個元素的開銷是固定的。
    3)LinkedList不支持高效的隨機元素訪問
    4)ArrayList的空間浪費主要體現在在list列表的結尾預留一定的容量空間,而LinkedList的空間花費則體現在它的每一個元素都需要消耗相當的空間

  3. 什麼是線程安全和非線程安全?
    答:線程安全就是在多線程環境下也不會出現數據不一致,而非線程安全就有可能出現數據不一致的情況。線程安全由於要確保數據的一致性,所以對資源的讀寫進行了控制,換句話說增加了系統開銷。所以在單線程環境中效率比非線程安全的效率要低些,但是如果線程間數據相關,需要保證讀寫順序,用線程安全模式。線程安全是通過線程同步控制來實現的,也就是synchronized關鍵字。

  4. Volatile關鍵字的作用?
    答:回答volatile關鍵之前,先說明一下與內存模型相關的概念和知識,然後分析了volatile關鍵字的實現原理,最後給出了幾個使用volatile關鍵字的場景。
    內存模型:計算機在執行程序時,每條指令都是在CPU中執行的,而執行指令過程中,勢必涉及到數據的讀取和寫入。由於程序運行過程中的臨時數據是存放在主存(物理內存)當中的,這時就存在一個問題,由於CPU執行速度很快,而從內存讀取數據和向內存寫入數據的過程跟CPU執行指令的速度比起來要慢的多,因此如果任何時候對數據的操作都要通過和內存的交互來進行,會大大降低指令執行的速度。因此在CPU裏面就有了高速緩存。也就是說,當程序在運行過程中,會將運算需要的數據從主存複製一份到CPU的高速緩存當中,那麼CPU進行計算時就可以直接從它的高速緩存讀取數據和向其中寫入數據,當運算結束之後,再將高速緩存中的數據刷新到主存當中
    在多核CPU中,每條線程可能運行於不同的CPU中,因此每個線程運行時有自己的高速緩存。如果一個變量在多個CPU中都存在緩存(一般在多線程編程時纔會出現),那麼就可能存在緩存不一致的問題。這就是著名的緩存一致性問題。通常稱這種被多個線程訪問的變量爲共享變量
    爲了解決緩存不一致性問題,通常來說有以下2種解決方法:
    1)通過在總線加LOCK #鎖的方式 => 由於在鎖住總線期間,其他CPU無法訪問內存,導致效率低下
    2)通過緩存一致性協議 => 當CPU寫數據時,如果發現操作的變量是共享變量,即在其他CPU中也存在該變量的副本,會發出信號通知其他CPU將該變量的緩存行置爲無效狀態,因此當其他CPU需要讀取這個變量時,發現自己緩存中緩存該變量的緩存行是無效的,那麼它就會從內存重新讀取。
    這2種方式都是硬件層面上提供的方式。
    併發編程的三個重要概念:原子性問題,可見性問題,有序性問題。
    1)原子性:即一個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行。
    2)可見性:指當多個線程訪問同一個變量時,一個線程修改了這個變量的值,其他線程能夠立即看得到修改的值。
    3)有序性:即程序執行的順序按照代碼的先後順序執行。這裏存在指令重排序(Instruction Reorder)的問題。
    什麼是指令重排序,一般來說,處理器爲了提高程序運行效率,可能會對輸入代碼進行優化,它不保證程序中各個語句的執行先後順序同代碼中的順序一致,但是它會保證程序最終執行結果和代碼順序執行的結果是一致的。指令重排序不會影響單個線程的執行,但是會影響到線程併發執行的正確性
    Java內存模型提供了哪些保證以及在java中提供了哪些方法和機制來讓保證在進行多線程編程時程序能夠正確執行
    1)原子性問題:在Java中,對基本數據類型的變量的讀取和賦值操作是原子性操作,即這些操作是不可被中斷的,要麼執行,要麼不執行。也就是說,只有簡單的讀取、賦值(而且必須是將數字賦值給某個變量,變量之間的相互賦值不是原子操作)纔是原子操作。Java內存模型只保證了基本讀取和賦值是原子性操作,如果要實現更大範圍操作的原子性,可以通過synchronized和Lock來實現。由於synchronized和Lock能夠保證任一時刻只有一個線程執行該代碼塊,那麼自然就不存在原子性問題了,從而保證了原子性。
    2)可見性問題:對於可見性,Java提供了volatile關鍵字來保證可見性當一個共享變量被volatile修飾時,它會保證修改的值會立即被更新到主存,當有其他線程需要讀取時,它會去內存中讀取新值。另外,通過synchronized和Lock也能夠保證可見性,synchronized和Lock能保證同一時刻只有一個線程獲取鎖然後執行同步代碼,並且在釋放鎖之前會將對變量的修改刷新到主存當中。因此可以保證可見性。
    3)有序性問題:在Java內存模型中,允許編譯器和處理器對指令進行重排序,但是重排序過程不會影響到單線程程序的執行,卻會影響到多線程併發執行的正確性。在Java裏面,可以通過volatile關鍵字來保證一定的“有序性”。另外可以通過synchronized和Lock來保證有序性,很顯然,synchronized和Lock保證每個時刻是有一個線程執行同步代碼,相當於是讓線程順序執行同步代碼,自然就保證了有序性。Java內存模型具備一些先天的“有序性”,即不需要通過任何手段就能夠得到保證的有序性,這個通常也稱爲 happens-before 原則如果兩個操作的執行次序無法從happens-before原則推導出來,那麼它們就不能保證它們的有序性,虛擬機可以隨意地對它們進行重排序
    深入剖析volatile關鍵字
    1)volatile關鍵字的兩層語義:①保證了不同線程對這個變量進行操作時的可見性,即一個線程修改了某個變量的值,這新值對其他線程來說是立即可見的。②禁止進行指令重排序。
    2)volatile保證原子性嗎?volatile沒辦法保證對變量的操作的原子性,可以使用的其他方法有:synchronized,Lock,AtomicInteger
    3)volatile能保證有序性嗎?volatile關鍵字能禁止指令重排序,所以volatile能在一定程度上保證有序性。這裏有兩層意思:①當程序執行到volatile變量的讀操作或者寫操作時,在其前面的操作的更改肯定全部已經進行,且結果已經對後面的操作可見;在其後面的操作肯定還沒有進行;②在進行指令優化時,不能將在對volatile變量訪問的語句放在其後面執行,也不能把volatile變量後面的語句放到其前面執行。
    4)volatile的原理和實現機制:“觀察加入volatile關鍵字和沒有加入volatile關鍵字時所生成的彙編代碼發現,加入volatile關鍵字時,會多出一個lock前綴指令”。lock前綴指令實際上相當於一個內存屏障(也成內存柵欄),內存屏障會提供3個功能:①它確保指令重排序時不會把其後面的指令排到內存屏障之前的位置,也不會把前面的指令排到內存屏障的後面;即在執行到內存屏障這句指令時,在它前面的操作已經全部完成;②它會強制將對緩存的修改操作立即寫入主存;③如果是寫操作,它會導致其他CPU中對應的緩存行無效。
    使用volatile關鍵字的場景:通常來說,使用volatile必須具備以下2個條件:①對變量的寫操作不依賴於當前值,②該變量沒有包含在具有其他變量的不變式中。使用volatile的幾個場景:狀態標記量、double check。

  5. JDK1.8有哪些變化?
    答:Lambda表達式、函數式接口、*方法引用和構造器調用、Stream API、接口中的默認方法和靜態方法、新時間日期API
    在jdk1.8中對hashMap等map集合的數據結構優化。hashMap數據結構的優化:原來的hashMap採用的數據結構是哈希表(數組+鏈表),hashMap默認大小是16,一個0-15索引的數組,如何往裏面存儲元素,首先調用元素的hashcode方法,計算出哈希碼值,經過哈希算法算成數組的索引值,如果對應的索引處沒有元素,直接存放,如果有對象在,那麼比較它們的equals方法比較內容,如果內容一樣,後一個value會將前一個value的值覆蓋,如果不一樣,在1.7的時候,後加的放在前面,形成一個鏈表,形成了碰撞,在某些情況下如果鏈表
    無限下去,那麼效率極低,碰撞是避免不了的;加載因子:0.75,數組擴容,達到總容量的75%,就進行擴容,但是無法避免碰撞的情況發生。在1.8之後,在數組+鏈表+紅黑樹來實現hashmap,當碰撞的元素個數大於8時 & 總容量大於64,會有紅黑樹的引入,除了添加之後,效率都比鏈表高,1.8之後鏈表新進元素加到末尾;ConcurrentHashMap (鎖分段機制),concurrentLevel,jdk1.8採用CAS算法(無鎖算法,不再使用鎖分段),數組+鏈表中也引入了紅黑樹的使用
    什麼是函數式接口?簡單來說就是隻定義了一個抽象方法的接口(Object類的public方法除外),就是函數式接口,並且還提供了註解:@FunctionalInterface
    Stream操作的三個步驟:創建stream => 中間操作(過濾、map)=> 終止操作
    新的日期API: LocalDate | LocalTime | LocalDateTime
    JVM變化:在JDK1.8之後,堆的永久區取消了,由元空間取代;在JDK 1.7中使用的是堆內存模型

  6. 垃圾回收機制中,對新生代和老生代瞭解嗎?原理是什麼?用到了哪些算法?
    答:先了解以下JVM的內容管理,其中包括判斷對象存活還是死亡的算法(引用計數算法、可達性分析算法),常見的垃圾收集算法(複製算法、分代收集算法等以及這些算法適用於什麼代)以及常見的垃圾收集器的特點(這些收集器適用於什麼年代的內存收集)。JVM運行時數據區由程序計數器、堆、虛擬機棧、本地方法棧、方法區部分組成JVM內存結構由程序計數器、堆、棧、本地方法棧、方法區等部分組成,結構圖如下所示:
    JVM運行時數據區結構圖和JVM內存結構圖
    ①程序計數器,也指pc寄存器:幾乎不佔有內存。用於取下一條執行的指令
    ②堆:所有通過new創建的對象的內存都在堆中分配,其大小可以通過-Xmx和-Xms來控制。堆被劃分爲新生代和老生代,新生代又被進一步劃分爲Eden和Survivor區,最後Survivor由FromSpace和ToSpace組成,(也指s0,s1)結構圖如下所示:
    JVM中新生代與老生代結構圖
    新生代:新建的對象都是用新生代分配內存,Eden空間不足的時候,會把存活的對象轉移到Survivor中,新生代大小可以由-Xmn來控制,也可以用-XX:SurvivorRatio來控制Eden和Survivor的比例。
    舊生代:用於存放新生代中經過多次垃圾回收仍然存活的對象。
    ③棧:每個線程執行每個方法的時候都會在棧中申請一個棧幀,每個棧幀包括局部變量區和操作數棧,用於存放此次方法調用過程中的臨時變量、參數和中間結果。
    ④本地方法棧:用於支持native方法的執行,存儲了每個native方法調用的狀態
    ⑤方法區:存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用永久代(PermanetGeneration)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值。
    JVM的垃圾回收機制:JVM分別對新生代和舊生代採用不同的垃圾回收機制。
    1)新生代的GC:新生代通常存活時間較短,因此基於複製算法來進行回收,所謂複製算法就是掃描出存活的對象,並複製到一塊新的完全未使用的空間中,對應於新生代,就是在Eden和其中一個Survivor,複製到另一個之間Survivor空間中然後清理掉原來就是在Eden和其中一個Survivor中的對象。新生代採用空閒指針的方式來控制GC觸發指針保持最後一個分配的對象在新生代區間的位置,當有新的對象要分配內存時,用於檢查空間是否足夠,不夠就觸發GC。當連續分配對象時,對象會逐漸從eden到 survivor,最後到老年代。在執行機制上JVM提供了串行GC(SerialGC)、並行回收GC(ParallelScavenge)和並行GC(ParNew)
    ①串行GC:在整個掃描和複製過程採用單線程的方式來進行,適用於單CPU、新生代空間較小及對暫停時間要求不是非常高的應用上,是client級別默認的GC方式,可以通過-XX:+UseSerialGC來強制指定
    ②並行回收GC:在整個掃描和複製過程採用多線程的方式來進行,適用於多CPU、對暫停時間要求較短的應用上,是server級別默認採用的GC方式,可用**-XX:+UseParallelGC來強制指定**,用**-XX:ParallelGCThreads=4來指定線程數**
    ③並行GC:與老生代的併發GC配合使用
    2)老生代的GC:老生代與新生代不同,對象存活的時間比較長,比較穩定,因此採用標記(Mark)算法來進行回收,所謂標記就是掃描出存活的對象,然後再進行回收未被標記的對象,回收後對用空出的空間要麼進行合併,要麼標記出來便於下次進行分配,總之就是要減少內存碎片帶來的效率損耗。在執行機制上JVM提供了串行 GC(SerialMSC)、並行GC(parallelMSC)和併發GC(CMS),具體算法細節還有待進一步深入研究。
    補充知識:JVM中堆的內存管理
    Java 中的堆是 JVM 所管理的最大的一塊內存空間,主要用於存放各種類的實例對象。在 Java 中,堆被劃分成兩個不同的區域:新生代 ( Young )、老年代 ( Old )新生代 ( Young ) 又被劃分爲三個區域:Eden、From Survivor、To Survivor。這樣劃分的目的是爲了使 JVM 能夠更好的管理堆內存中的對象,包括內存的分配以及回收。堆大小 = 新生代 + 老年代。其中,堆的大小可以通過參數 –Xms、-Xmx 來指定。默認的,新生代 ( Young ) 與老年代 ( Old ) 的比例的值爲 1:2 ( 該值可以通過參數 –XX:NewRatio 來指定),默認的,Edem : from : to = 8 :1 : 1 ( 可以通過參數–XX:SurvivorRatio 來設定 ), JVM 每次只會使用 Eden 和其中的一塊 Survivor 區域來爲對象服務,所以無論什麼時候,總是有一塊Survivor。 因此,新生代實際可用的內存空間爲 9/10 ( 即90% )的新生代空間。
    GC堆: Java 中的堆也是 GC 收集垃圾的主要區域。GC 分爲兩種:Minor GC、FullGC ( 或稱爲 Major GC )
    1)Minor GC 是發生在新生代中的垃圾收集動作,所採用的是複製算法
    2)Full GC 是發生在老年代的垃圾收集動作,所採用的是標記-清除算法
    區域是空閒着的。
    下面只列舉其中的幾個常用和容易掌握的配置選項
    -Xms:初始堆大小。如:-Xms256m
    -Xmx:最大堆大小。如:-Xmx512m
    -Xmn:新生代大小。通常爲 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間爲 = Eden + 1 個 Survivor,即 90%
    -Xss:JDK1.5+ 每個線程堆棧大小爲 1M,一般來說如果棧不是很深的話, 1M 是絕對夠用了的。
    -XX:NewRatio:新生代與老年代的比例,如 –XX:NewRatio=2,則新生代佔整個堆空間的1/3,老年代佔2/3
    -XX:SurvivorRatio:新生代中 Eden 與 Survivor 的比值。默認值爲 8。即 Eden 佔新生代空間的 8/10,另外兩個 Survivor 各佔 1/10
    -XX:PermSize:永久代(方法區)的初始大小
    -XX:MaxPermSize:永久代(方法區)的最大值
    -XX:+PrintGCDetails:打印 GC 信息
    -XX:+HeapDumpOnOutOfMemoryError:讓虛擬機在發生內存溢出時 Dump 出當前的內存堆轉儲快照,以便分析用

  7. 如果有一個環形引用,如何對其進行垃圾回收?
    答:1. 如何判定對象爲垃圾對象:引用計數法,可達性分析法;2.如何回收:回收策略(標記-清除算法,複製算法,標記-整理算法,分帶收集算法),垃圾回收器(serial,parnew,Cms,G1);3. 何時回收
    判定對象爲垃圾的方法
    1)引用計數法:在對象中添加一個引用計數器,當有地方引用這個對象的時候,引用技術器得值就+1,當引用失效的時候,計數器得值就-1。算法缺點:當某個引用被收集時,下個引用並不會清0,因此不被回收造成內存泄露。
    2)可達性分析法:可達性分析法就是從GCroot結點開始,看能否找到對象。GCroot結點開始向下搜索,路徑稱爲引用鏈,當對象沒有任何一條引用鏈鏈接的時候,就認爲這個對象是垃圾,並進行回收。那麼什麼是GCroot呢(虛擬機在哪查找GCroot):①虛擬機棧(局部變量表),②方法區的類屬性所引用的對象,③方法區中常量所引用的對象,④本地方法棧中引用的對象。目前主流JVM採用的垃圾判定算法就是可達性分析法。
    垃圾回收算法
    1)標記清除算法。存在的問題:效率問題;內存小塊過多。
    2)複製算法。將Eden中需要回收的對象放到Survivor,然後清除。也就是兩個Survivor中進行復制與清除。這裏我們即提高了效率,又減少了內存分配。如果Survivor不夠放,那就扔到老年代裏,或者其他方法,有內存作擔保。複製算法主要針對新生代內存收集方法。
    3)標記整理算法:標記-整理算法主要針對的是老年代內存收集方法。主要步驟:標記-整理-清除
    4)分代收集算法:分代收集算法是根據內存的分代選擇不同的算法。對於新生代,一般選擇複製算法。對於老年代,一般選擇標記-整理-清除算法。
    垃圾回收器
    1)Serial收集器。特點:出現的最早的,發展最悠久的垃圾收集器;單線程垃圾收集器;主要針對新生代內存進行收集;缺點:慢。用處:在客戶端上運行還是比較有效;沒有線程的開銷,所以在客戶端還是比較好用的。
    2)ParNew收集器。特點:由單線程變成了多線程垃圾收集器;如果要用CMS進行收集的話,最好採用ParNew收集器。實現原理都是複製算法。缺點:性能較慢。
    3)Parallel Scavenge 收集器。主用算法:複製算法(新生代收集器);吞吐量 = (執行用戶代碼消耗的時間)/(執行用戶代碼的時間)+ 垃圾回收時所佔用的時間;優點:吞吐量優化(CPU用於運行用戶代碼的時間與CPU消耗的總時間的比值)
    關於控制吞吐量的參數如下:
    ① -XX:MaxGCPauseMills #垃圾收集器的停頓時間
    ② -XX:GCTimeRatio #吞吐量大小
    當停頓時間過小時,內存對應變小,回收的頻率增大。因此第一個參數需要設置的合理才比較好。第二個參數值越大,吞吐量越大,默認是99,(垃圾回收時間最多隻能佔到1%)
    4)CMS收集器(Concurrent Mark Sweep)。採用算法:標記清除算法。
    工作過程:初始標記(可達性分析法)->併發標記->重新標記(爲了修正併發期間,因對象重新運作而修正)->併發清理(直接清除了)
    優點:併發收集,低停頓
    缺點:佔用大量的CPU資源,無法處理浮動垃圾,出現ConcurrentMode Failure,空間碎片
    CMS是一個併發的收集器。目標是:減少延遲,增加響應速度。總的來說:客戶端可用,服務端最好不用。
    5)G1收集器(面向服務端)。優勢:集中了前面所有收集器的優點;G1能充分利用了多核的並行特點,能縮短停頓時間;分代收集(分成各種Region);空間整合(類似於標記清理算法);可預測的停頓()。
    步驟:初始標記->併發標記->最終標記->篩選回收
    在目前發佈的Java8中,默認的虛擬機使用的是HotSpot(另一種是JRockit),對應的垃圾回收機制也就是HotSpot的GC機制;而JVM HotSpot使用的就是可達性分析法,即根搜索算法

  8. 序列化和反序列化
    答:1)序列化:把對象轉換爲字節序列存儲於磁盤或者進行網絡傳輸的過程稱爲對象的序列化。對象序列化過程可以分爲兩步:第一: 將對象轉換爲字節數組;第二: 將字節數組存儲到磁盤
    2)反序列化:把磁盤或網絡節點上的字節序列恢復到內存中的對象的過程稱爲對象的反序列化。可以是文件中的,也可以是網絡傳輸過來的。
    3)對象的序列化和反序列化主要就是使用ObjectOutputStream 和 ObjectInputStream

Python部分

  1. 介紹Python的項目經驗
    答:結合實際情況回答

  2. Python的多線程與多進程
    答:1)什麼是線程:線程是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一條線程指的是進程中一個單一順序的控制流,一個進程中可以併發多個線程,每條線程並行執行不同的任務一個線程是一個execution context(執行上下文),即一個cpu執行時所需要的一串指令
    2)什麼是進程:一個程序的執行實例就是一個進程。每一個進程提供執行程序所需的所有資源(進程本質上是資源的集合);一個進程有一個虛擬的地址空間、可執行的代碼、操作系統的接口、安全的上下文(記錄啓動該進程的用戶和權限等等)、唯一的進程ID、環境變量、優先級類、最小和最大的工作空間(內存空間),還要有至少一個線程;每一個進程啓動時都會最先產生一個線程,即主線程,然後主線程會再創建其他的子線程
    3)進程與線程的區別:
    ①同一個進程中的線程共享同一內存空間,但是進程之間是獨立的
    ②同一個進程中的所有線程的數據是共享的(進程通訊),進程之間的數據是獨立的
    ③對主線程的修改可能會影響其他線程的行爲,但是父進程的修改(除了刪除以外)不會影響其他子進程
    線程是一個上下文的執行指令,而進程則是與運算相關的一簇資源。
    同一個進程的線程之間可以直接通信,但是進程之間的交流需要藉助中間代理來實現
    創建新的線程很容易,但是創建新的進程需要對父進程做一次複製
    一個線程可以操作同一進程的其他線程,但是進程只能操作其子進程
    線程啓動速度快進程啓動速度慢(但是兩者運行速度沒有可比性)。
    4)P

  3. 是否瞭解Python的協程?

  4. Python的裝飾器的用法和原理

Linux部分

  1. 如何查看當前系統CPU使用率最高的線程和進程?
    答: 進程查看的命令是ps和top。進程調度的命令有at,crontab,batch,kill。
    (gdb)info threads 顯示當前可調試的所有線程,每個線程會有一個GDB爲其分配的ID,後面操作線程的時候會用到這個ID。 前面有*的是當前調試的線程。
    (gdb)thread ID 切換當前調試的線程爲指定ID的線程。
    (gdb)thread apply ID1 ID2 command 讓一個或者多個線程執行GDB命令command。
    (gdb)thread apply all command 讓所有被調試線程執行GDB命令command。
    (gdb)set scheduler-locking off|on|step 估計是實際使用過多線程調試的人都可以發現,在使用step或者continue命令調試當前被調試線程的時候,其他線程也是同時執行的,怎麼只讓被調試程序執行呢?通過這個命令就可以實現這個需求。 off 不鎖定任何線程,也就是所有線程都執行,這是默認值。 on 只有當前被調試程序會執行。 step 在單步的時候,除了next過一個函數的情況(熟悉情況的人可能知道,這其實是一個設置斷點然後continue的行爲)以外,只有當前線程會執行。
    (gdb) bt 察看所有的調用棧
    (gdb) f 3 調用框層次
    (gdb) i locals 顯示所有當前調用棧的所有變量
  2. awk實現一條命令將某一個目錄裏的所有文件分別進行備份,後綴爲.bak
  3. 簡述進程的啓動、終止的方式以及如何進行進程的查看.
    答:在Linux中啓動一個進程有手工啓動和調度啓動兩種方式:
    (1)手工啓動:用戶在輸入端發出命令,直接啓動一個進程的啓動方式可以分爲:①前臺啓動:直接在SHELL中輸入命令進行啓動。②後臺啓動:啓動一個目前並不緊急的進程,如打印進程.
    (2)調度啓動:系統管理員根據系統資源和進程佔用資源的情況,事先進行調度安排,指定任務運行的時間和場合,到時候系統會自動完成該任務。經常使用的進程調度命令爲:at、batch、crontab。

計算機網絡部分

  1. 網絡的7層協議
  • OSI分層 (7層):物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層。
  • TCP/IP分層(4層):網絡接口層、 網際層、運輸層、 應用層。
  • 五層協議 (5層):物理層、數據鏈路層、網絡層、運輸層、 應用層。
    補充知識:每一層的協議如下:
  • 物理層:RJ45、CLOCK、IEEE802.3 (中繼器,集線器,網關)
  • 數據鏈路:PPP、FR、HDLC、VLAN、MAC (網橋,交換機)
  • 網絡層:IP、ICMP、ARP、RARP、OSPF、IPX、RIP、IGRP、 (路由器)
  • 傳輸層:TCP、UDP、SPX
  • 會話層:NFS、SQL、NETBIOS、RPC
  • 表示層:JPEG、MPEG、ASII
  • 應用層:FTP、DNS、Telnet、SMTP、HTTP、WWW、NFS
  1. TCP的4次分手過程。如果大量出現close_wait狀態,可能是什麼原因?
    答:1)Client發起斷開連接,給Server發送FIN,進入FIN_WAIT1狀態,表示Client想主動斷開連接;2)Server接受到FIN字段後,會繼續發送數據給Client端,併發送ACK給Client端,表明自己知道了,但是還沒有準備好斷開,請等我的消息;3)當Server確定自己的數據已經發送完成,就發送FIN到Client;4)Client接受到來自Server的FIN,發送ACK給Server端,表示可以斷開連接了,再等待2MSL,沒有收到Server端的數據後,表示可以正常斷開連接。如下圖所示:
    TCP的四次揮手補充知識:TCP的三次握手
    補充問題:**爲什麼TIME_WAIT狀態還需要等2
    MSL(Max SegmentLifetime,最大分段生存期)秒之後才能返回到CLOSED狀態呢?**
    答:因爲雖然雙方都同意關閉連接了,而且握手的4個報文也都發送完畢,按理可以直接回到CLOSED狀態(就好比從SYN_SENT狀態到ESTABLISH狀態那樣),但是我們必須假想網絡是不可靠的,你無法保證你最後發送的ACK報文一定會被對方收到,就是說對方處於LAST_ACK狀態下的SOCKET可能會因爲超時未收到ACK報文,而重發FIN報文,所以這個TIME_WAIT狀態的作用就是用來重發可能丟失的ACK報文
    補充問題:爲什麼要4次揮手?
    答:TCP協議是一種面向連接的、可靠的、基於字節流的傳輸層通信協議,是一個全雙工模式:
    1、當主機A確認發送完數據且知道B已經接受完了,想要關閉發送數據口(當然確認信號還是可以發),就會發FIN給主機B。
    2、主機B收到A發送的FIN,表示收到了,就會發送ACK回覆。
    3、但這是B可能還在發送數據,沒有想要關閉數據口的意思,所以FIN與ACK不是同時發送的,而是等到B數據發送完了,纔會發送FIN給主機A。
    4、A收到B發來的FIN,知道B的數據也發送完了,回覆ACK, A等待2MSL以後,沒有收到B傳來的任何消息,知道B已經收到自己的ACK了,A就關閉鏈接,B也關閉鏈接了。
    確保數據能夠完成傳輸。
    補充問題:如果已經建立了連接,但是客戶端突然出現故障了怎麼辦?
    答:TCP還設有一個保活計時器,顯然,客戶端如果出現故障,服務器不能一直等下去,白白浪費資源。服務器每收到一次客戶端的請求後都會重新復位這個計時器,時間通常是設置爲2小時,若兩小時還沒有收到客戶端的任何數據,服務器就會發送一個探測報文段,以後每隔75分鐘發送一次。若一連發送10個探測報文仍然沒反應,服務器就認爲客戶端出了故障,接着就關閉連接。

  2. 瀏覽器和服務器之間如何建立連接?
    答:
    補充知識:HTTP的長連接和短連接?
    HTTP的長連接和短連接本質上是TCP長連接和短連接。HTTP屬於應用層協議.

  • 短連接:瀏覽器和服務器每進行一次HTTP操作,就建立一次連接,但任務結束就中斷連接。
  • 長連接:當一個網頁打開完成後,客戶端和服務器之間用於傳輸HTTP數據的TCP連接不會關閉,如果客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經建立的連接。Keep-Alive不會永久保持連接,它有一個保持時間,可以在不同的服務器軟件(如Apache)中設定這個時間。實現長連接要客戶端和服務端都支持長連接。
  • TCP短連接: client向server發起連接請求,server接到請求,然後雙方建立連接。client向server發送消息,server迴應client,然後一次讀寫就完成了,這時候雙方任何一個都可以發起close操作,不過一般都是client先發起 close操作。短連接一般只會在 client/server間傳遞一次讀寫操作
  • TCP長連接: client向server發起連接,server接受client連接,雙方建立連接。Client與server完成一次讀寫之後,它們之間的連接並不會主動關閉,後續的讀寫操作會繼續使用這個連接。
  1. IO中同步與異步,阻塞與非阻塞區別
    答:同步和異步關注的是消息通信機制 (synchronous communication/asynchronous communication)。所謂同步,就是在發出一個調用時,在沒有得到結果之前,該調用不返回。但是一旦調用返回,就得到返回值了。換句話說,就是由調用者主動等待這個調用的結果。而異步則是相反,調用在發出之後,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出後,調用者不會立刻得到結果。而是在調用發出後,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用
    阻塞和非阻塞關注的是程序在等待調用結果(消息,返回值)時的狀態阻塞調用是指調用結果返回之前,當前線程會被掛起。函數只有在得到結果之後纔會返回。非阻塞不能立刻得到結果之前,該函數不會阻塞當前線程,而會立刻返回。

  2. DNS進行域名解析的過程.
    答:客戶端發出DNS請求翻譯IP地址或主機名,DNS服務器在收到客戶機的請求後:
    (1)檢查DNS服務器的緩存,若查到請求的地址或名字,即向客戶機發出應答信息;
    (2)若沒有查到,則在數據庫中查找,若查到請求的地址或名字,即向客戶機發出應答信息;
    (3)若沒有查到,則將請求發給根域DNS服務器,並依序從根域查找頂級域,由頂級查找二級域,二級域查找三級,直至找到要解析的地址或名字,即向客戶機所在網絡的DNS服務器發出應答信息,DNS服務器收到應答後先在緩存中存儲,然後將解析結果發給客戶機;
    (4)若沒有找到,則返回錯誤信息。

  3. 在瀏覽器中輸入www.163.com後執行的全部過程
    答:1、客戶端瀏覽器通過DNS解析到www.163.com的IP地址210.11.27.79,通過這個IP地址找到客戶端到服務器的路徑。客戶端瀏覽器發起一個HTTP會話到210.11.27.79,然後通過TCP進行封裝數據包,輸入到網絡層。
    2、在客戶端的傳輸層,把HTTP會話請求分成報文段,添加源和目的端口,如服務器使用80端口監聽客戶端的請求,客戶端由系統隨機選擇一個端口如5000,與服務器進行交換,服務器把相應的請求返回給客戶端的5000端口。然後使用IP層的IP地址查找目的端。
    3、客戶端的網絡層不用關心應用層或者傳輸層的東西,主要做的是通過查找路由表確定如何到達服務器,期間可能經過多個路由器,這些都是由路由器來完成的工作,不作過多的描述,無非就是通過查找路由表決定通過那個路徑到達服務器。
    4、客戶端的鏈路層,包通過鏈路層發送到路由器,通過鄰居協議查找給定IP地址的MAC地址,然後發送ARP請求查找目的地址,如果得到迴應後就可以使用ARP的請求應答交換的IP數據包現在就可以傳輸了,然後發送IP數據包到達服務器的地址。

其他題目收集

Python部分

  • 迭代器生成器,生成器是如何實現迭代的?
  • list實現
  • import一個包時過程是怎麼樣的?
  • 裝飾器實現
  • 菱形繼承
  • 內存垃圾回收:分代回收細節
  • WSGI
  • uWSGI進程模型
  • 比較c語言和Python語言中的異步
  • epoll原理
  • Python裏的eval
  • Tornado框架
  • PythonGIL鎖
  • Python垃圾回收與內存泄露
  • 虛擬內存與物理內存區別

Java部分

  • 多線程安全問題
  • 併發和並行的區別
  • Java的併發安全機制(答了synchronized、ReentrantLock、CAS)
  • String、StringBuilder、StringBuffer的區別和應用場景
  • String a=“abc” String b=“abc” ,a等於b嗎?常量池位於JVM的哪裏?String提供了什麼方法使用常量池?(intern)
  • string爲什麼不會變
  • collection與collections區別

數據庫部分

  • MySQL B+樹
  • MySQL聯合索引
  • SQL的左連接、右連接等連接
  • SQL的索引數據結構
  • B+樹和二叉查詢樹的區別,爲什麼要降低樹的高度
  • MySQL優化(回答索引、拆分等,回答不夠)

算法部分

  • 堆排序
  • 求二叉樹深度
  • Top k問題
  • 二叉樹的鏡像
  • 如何判斷鏈表有沒有環
  • 如何用兩個棧表示一個隊列
  • 不用中間元素交換兩個元素的方法,(答:使用異或),又問:不使用異或有什麼缺點。。
  • 億級元素top k,答:k大小小頂堆,又問:如何多線程改進
  • 遞歸翻轉鏈表
  • 多個有序數組合併爲一個
  • 順時針打印數組
  • 寫二分查找(
    • 寫完了問爲什麼要left+(right-left)/2(答怕溢出)
    • int 的最大值是?
    • (right-left)/2會不會出現浮點數
    • 二分查找有什麼要求(數組有序,升序降序都可以嗎?)
    • 能不能寫個代碼讓升序降序都滿足)
  • leetcode 75題
  • leetcode 55
  • 快速排序的原理,手寫快速排序,哪些排序是穩定的?
  • 一個數組中假如有一個數出現頻率達到了百分之五十以上,怎麼找到這個數?

計算機網絡

  • TCP與UDP的區別
    答:從9個方面比較:
    1.連接: TCP面向連接,UDP面向非連接
    2.可靠性: TCP可靠, UDP非可靠
    3.有序性: TCP有序, UDP不保證有序
    4.速度: TCP慢,UDP快
    5.量級: TCP重量級, UDP輕量級
    6.擁塞控制或流量控制: TCP有, UDP沒有
    7 TCP面向字節流,無記錄邊界; UDP面向報文,有記錄邊界
    8 TCP只能單播; UDP可以廣播或組播
    9.應用場景: TCP效率低,準確性高; UDP效率高,準確性低

  • TCP 三次握手
    答:Server處於Listen狀態,表示服務器端的某個SOCKET處於監聽狀態,可以接受連接了:1)當Client端socket執行connect連接時,首先發送SVN報文到Server,進入SVN_SENT狀態,等待Server發送ACK;2)Server接受到SVN進入SVN_RCVD狀態,(很短暫,一般查詢不到),發送SVN+ACK給Client端;3)Client端接受到Server的ACK,發送ACK給Server,Server接收到後進入established狀態,Client也進入established狀態。如下圖所示:
    TCP的三次握手
    補充問題:爲什麼TCP連接要建立三次連接
    答:爲了防止失效的連接請求又傳送到主機,因而產生錯誤如果使用的是兩次握手建立連接,假設有這樣一種場景,客戶端發送了第一個請求連接並且沒有丟失,只是因爲在網絡結點中滯留的時間太長了,由於TCP的客戶端遲遲沒有收到確認報文,以爲服務器沒有收到,此時重新向服務器發送這條報文,此後客戶端和服務器經過兩次握手完成連接,傳輸數據,然後關閉連接。此時此前滯留的那一次請求連接,網絡通暢了到達了服務器,這個報文本該是失效的,但是,兩次握手的機制將會讓客戶端和服務器再次建立連接,這將導致不必要的錯誤和資源的浪費。如果採用的是三次握手,就算是那一次失效的報文傳送過來了,服務端接受到了那條失效報文並且回覆了確認報文,但是客戶端不會再次發出確認。由於服務器收不到確認,就知道客戶端並沒有請求連接。

  • 如果一個客戶端不理會服務端發來的ack,一直重發syn怎麼辦?(我理解爲類似syn洪水攻擊)

  • 擁塞控制 流量控制
    答:TCP/IP的流量控制:利用滑動窗口實現流量控制,如果發送方把數據發送得過快,接收方可能會來不及接收,這就會造成數據的丟失。所謂流量控制就是讓發送方的發送速率不要太快,要讓接收方來得及接收。TCP爲每一個連接設有一個持續計時器(persistence timer)。只要TCP連接的一方收到對方的零窗口通知,就啓動持續計時器。若持續計時器設置的時間到期,就發送一個零窗口控測報文段(攜1字節的數據),那麼收到這個報文段的一方就重新設置持續計時器。
    TCP擁塞控制:防止過多的數據注入到網絡中,這樣可以使網絡中的路由器或鏈路不致過載。擁塞控制所要做的都有一個前提:網絡能夠承受現有的網絡負荷。擁塞控制是一個全局性的過程,涉及到所有的主機、路由器,以及與降低網絡傳輸性能有關的所有因素。擁塞控制代價:需要獲得網絡內部流量分佈的信息。在實施擁塞控制之前,還需要在結點之間交換信息和各種命令,以便選擇控制的策略和實施控制。這樣就產生了額外的開銷。擁塞控制還需要將一些資源分配給各個用戶單獨使用,使得網絡資源不能更好地實現共享。

  • Socket編程:raw_socket

  • http cookie具體所有相關內容

  • http傳輸一個二進制文件的所有過程

  • post和get的區別

操作系統

  • 編譯原理相關
  • 從用戶態到內核態的彙編級過程
  • 中斷以及系統調用
  • 全局變量和局部變量都保存在哪兒
  • LRU(O(1)時間複雜度)
  • 進程間通信
  • 如何從用戶態到內核態
  • 介紹進程跟線程,進程之間的通信

Linux部分

  • 部署項目怎麼寫shell腳本
  • 查看進程用什麼指令(jps?)
    • jps是java進程的,非java進程用什麼看?
  • Linux系統,怎麼找到某個端口運行的程序的絕對地址
  • ps指令
  • 軟連接和硬鏈接,linux 目錄默認inode多少

框架

  • MVC框架

其他

  • 100個石頭,每個人一次可以摸1-5個,甲先摸,問甲有沒有必贏的方法?
  • 有沒有讀Python源碼?
  • 遊戲模型如何確認人身上的膠囊體是否被激光射中?
  • 網頁相似性比較
  • RPC框架
  • Git常用指令
  • 服務感知(客戶端如何感知服務端狀態)
  • 如果地球自轉速度降低一半,會怎麼樣?

參考資料

  • https://blog.csdn.net/diaopai5230/article/details/101210745
  • https://blog.csdn.net/u010843421/article/details/82026427
  • https://blog.csdn.net/shantf93/article/details/79775702
  • https://blog.csdn.net/lqglqglqg/article/details/48293141
  • https://blog.csdn.net/qq_37113604/article/details/80836025
  • https://www.cnblogs.com/Ferda/p/10833863.html
  • https://www.cnblogs.com/dolphin0520/p/3920373.html
  • https://www.cnblogs.com/godoforange/p/11552865.html
  • https://www.cnblogs.com/whatisfantasy/p/6440585.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章