阿里面試官用HashMap把我問倒了

EhuoWeirdo發表於2021-05-12

本人是一名大三學生,最近在找暑期實習,其中也面試過兩次阿里,一次菜鳥網路部門、一次網商銀行部門,當然我都失敗了,同時也讓我印象很深刻,因此記錄了其中一些面試心得,我覺得這個問題很值得分享,因此分享給大家

你能說一下HashMap的實現原理嗎?

對於這個問題,我當時覺得這個問題太小菜一碟了,於是照著自己之前準備的開始巴拉巴拉介紹HashMap,當我說到雜湊衝突時,面試官打斷了我,問我,你知道HashMap如何解決雜湊衝突的嗎?這個我想都沒想直接說鏈地址法,於是面試官又繼續問,那你還知道有哪些解決Hash衝突的方法,我當時整好記得一個開放定址法,於是面試官又繼續問

你能說一下開放定址法的原理嗎?

到這裡我已經有點懵了,我就照著字面意思解釋了一番,標準解答如下:當雜湊碰撞發生時,從發生碰撞的那個單元起,按照一定的次序,從雜湊表中尋找一個空閒的單元,然後把發生衝突的元素存入到該單元。

於是面試官又問,如果用開放定址法實現HashMap,能刪除節點嗎?此時我已語塞,因為我知道不管是回答能還是不能,他下一句肯定是為什麼能或者為什麼不能

面試關看我這裡不會,於是換了個方向,接著問

你知道開放定址法有哪些地方用到,或者說有哪些應用?

整好,我學過ThreadLocal,並當時瞭解過ThreadLocal的底層是使用ThreadLocalMap實現的,而ThreadLocalMap 的底層解決雜湊衝突的方式正是鏈地址法,於是我將這些說了出來,於是面試官接著問

說說你對ThreadLocal的理解

於是我照著自己的理解介紹了一下ThreadLocal,面試官接著問,ThreadLocal有哪些應用,我答在與資料庫進行互動的時候,需要保證資料庫連線的一致性,此時就用到了ThreadLocal保證同一個事物中對資料庫的操作是用的同一個資料庫連線(其實當時我只想的到這個了),於是面試官接著問

ThreadLocal存在哪些問題

學過ThreadLocal 的人應該都知道,ThreadLocal其實是存在記憶體洩漏的問題,一個是key的記憶體洩漏,一個是value的記憶體洩漏,面試官接著問,那你說說ThreadLocal是如何解決這些問題的,我答:

  • 對於key 的記憶體洩漏:ThreadLocalMap 的key實際上是一個弱引用,當ThreaLocal物件為null時,這個key就會被回收,就不會造成記憶體洩漏
  • 對於value的記憶體洩漏:每次使用完ThreadLocal中存的變數都要記得remove,這樣就不會造成value 的記憶體洩漏

於是面試關接著問,既然key採用了弱引用的方式解決記憶體洩漏,那為什麼value不也用弱引用的方式解決記憶體洩漏,我當時其實都不知道該怎麼答了,我照著自己的理解說:對於value的記憶體洩漏,之所以沒有采用弱引用的方式,是因為不清楚這個Value除了map的引用還是否還存在其他引用,如果不存在其他引用,當GC的時候就會直接將這個value幹掉了,而此時我們的ThreadLocal還處於使用期間,就會造成Value為null的錯誤

但是面試官仍然沒有打算放過我,然後接著問,為什麼弱引用就能解決記憶體洩漏問題,其實我覺得當時他的意思是

把Java 的引用資料型別給介紹一下?

我答:Java有強引用、軟引用、弱引用、虛引用。我分別按照自己的理解將這些引用介紹了一下,於是面試官逮這虛引用跟我聊起來了,他說

虛引用有什麼用

其實我在Java引用資料型別還有一些瞭解,所以就介紹了下虛引用,於是面試官說那平常有哪些場景會用到,我說常見的就是NIO通訊的時候,因為我之前做過一個專案與硬體資料上傳有關,當時我的服務端就用的NIO,我接著說,比如網路卡傳來資料,會先將該資料拷貝到作業系統記憶體中,如果JVM要用這部分資料,則會再從作業系統的記憶體中將這部分資料拷貝到JVM記憶體中,這樣的過程就進行了多次拷貝,且耗時間,因此allocateDirect這樣少一次拷貝的效率會很高,這樣的操作也被稱為零拷貝,NIO底層就用到了零拷貝的原理。在這種零拷貝的情況下,虛引用就誕生了,虛引用通常指向作業系統記憶體空間的資料,當虛引用要被回收時,就會把該虛引用放到事件佇列裡,GC也會時不時檢查佇列,會檢查佇列裡的虛引用所指向的記憶體需不需要被回收,如果需要就直接將其回收,同時將改虛引用出隊,這樣就實現了虛引用監控的作用,實現了通過虛引用清除OS空間裡的記憶體

面試官看我說到了NIO,於是就著NIO開始問我

為什麼當時專案用NIO不用IO

其實這個地方我還是能答的,因為我當時專案最開始的確是使用的IO方式接收資料,之後才改成的NIO,於是我回答因為IO底層採用的多路複用機制,效率會比IO高很多,於是面試官接著問

說一說IO多路複用機制是怎樣的

其實到這裡我已經感覺到呼吸困難了,我照著自己的理解介紹了IO多路複用機制(當時感覺介紹的很通俗,不夠專業)

於是面試官接著問

那你介紹下select、poll、epoll

select

select(阻塞函式)其實就是將對FD(標誌位)資料的集合判斷從原來的使用者態到交給核心態管理(將Rset從使用者態拷貝到了核心態),核心態會快很多,如果判斷有資料

  • 將FD置位,表示此時有資料來了
  • 將select返回,不再阻塞

之後判斷那一個FD被置位了,於是就行取資料處理

select使用的1024的bitmap存資料

缺點:

  • fd_size有限制1024bitmap
  • FDset不可重用
  • 使用者態到核心態的拷貝開銷
  • O(n)再次遍歷

poll

poll(阻塞函式),工作原理與select很相似, 但是poll沒有采用bitmap,採用的pollfd儲存(基於結構體儲存fd)

struct pollfd {
    int fd;
    short events;
    short revents;
}

有資料:

  • pollfd.revents置位
  • poll返回,不再阻塞

執行之後的操作,執行之後再將pollfd.revents設定為0

缺點:

  • 使用者態到核心態的拷貝開銷
  • O(n)再次遍歷

epoll

epoll,最新的一種IO多路複用的函式,使用者態和核心態共享epfd陣列,核心用於判斷哪個fd有資料到來,不需要使用者態到核心態的拷貝,不需要輪詢,時間負責度O(1)

有資料:

  • 置位,通過重排置位,將陣列中有資料的fd放在前面的位置
  • 返回,有返回值,返回一共有多少個fd觸發了事件,這樣可以實現遍歷複雜度為O(1)

Redis、Ngnix都是使用的epoll,JavaNIO在Linux系統下也是採用的epool實現的

其實到這裡我已經答不出來了,因為我作業系統學的其實並不好,上面有些東西也是我之後總結出來補上去的

上面都是我個人的真實經歷,其實有很多點都可以深究去挖掘,我這篇文章的問法可能只是一個岑天大樹的一個小分支,錄製這個視訊的意義就是想跟大家分享分享面經,也是為了告訴大家,知識網路體系的建立很重要,尤其是對於想要面試大廠的小夥伴本。B站地址:https://space.bilibili.com/476743659

相關文章