裝逼的面試官和裝逼的程序員程序員
我面試別人的時候,常常是按這種路子來面試:面試
看簡歷和麪試題,從簡歷和麪試題上找到一些技術點,而後跟應聘者聊。算法
聊某個技術點的時候,應聘者的回答會牽涉到其餘的技術點,而後我會一一記下來,再挑一些我感興趣的技術點繼續和他聊數據庫
有時候應聘者爲了裝逼會牽涉出不少技術點,他本身可能只是知道個名字就說出來了。編程
這樣的話,能很輕易的發現應聘者的水平,也能知道他提供的面試信息的水分有多少。函數
---------------------spa
然而,有的時候會碰到一些我本身都不熟悉的技術點(好比說算法、圖形、WF方面的),code
那我就儘可能不跟人家聊這個,或者直接說,這個我也不太懂,對象
可是,有不少面試官跟應聘者聊天的時候,爲了裝B,會天馬行空的聊出不少本身都不是很熟悉的技術點。blog
這樣來應聘的人就能很清楚的知道,未來本身是跟着一個什麼樣的老大,在一個什麼樣的團隊混了。
----------------------
大概在今年年初的時候,我面試過一個朋友,各方面都還不錯,
他主動提到垃圾收集這個技術點,因而咱們就在這塊內容上聊起來
可是,我以爲他回答的內容,跟我想聽的內容,雖然有交集,但大部分仍是扯遠了(我相信他對這塊仍是比較清楚的)
就像有一個姑娘持續不斷的撩撥你,難受的不行,從那時開始就打算寫這篇文章了
(後來,個人面試建議是贊成錄用,但最終沒有加入咱們團隊,估計是人事或者薪資卡住了。)
能簡單聊一下垃圾收集的工做方式嗎?
運行.NET應用程序時,程序建立出來的對象都會被CLR跟蹤,
哪些對象還會被用到(存在引用關係);哪些對象不會再被用到(不存在引用關係),CLR都是有記錄的。
CLR會整理不會再被用到的對象,在恰當的時機,按必定的規則銷燬一部分對象,釋放出這些對象所佔用的內存。
-----------------
上面這段話,牽涉到了不少技術點:(如下這些技術點,簡單說一下,不深刻討論)
CLR是怎麼記錄對象引用關係的?
CLR會把對象關係作成一個「樹圖」,這樣標記他們的引用關係
CLR是怎麼釋放對象的內存的?
關鍵的技術是:CLR把沒用的對象轉移到一塊兒去,使內存連續,新分配的對象就在這塊連續的內存上建立,這樣作是爲了減小內存碎片(CLR不會移動大對象)
垃圾收集器按什麼規則收集垃圾對象?
CLR按對象在內存中的存活的時間長短,來收集對象。
時間最短的被分配到第0代,最長的被分配到第2代,一共就3代。
通常第0貸的對象都是較小的對象,第2代的對象都是較大的對象
第0代對象GC收集時間最短(毫秒級別),第2代的對象GC收集時間最長。
當程序須要內存時(或者程序空閒的時),GC會先收集第0代的對象,
收集完以後發現釋放的內存仍然不夠用,GC就會去收集第1代,第2代對象。(通常狀況是按這個順序收集的)
若是GC跑過了,內存空間依然不夠用,那麼就拋出了OutOfMemoryException異常。
GC跑過幾回以後,第0代的對象仍然存在,那麼CLR會把這些對象移動到第1代,第1代的對象也是這樣。
既然有了垃圾收集器,爲何還要Dispose方法和析構函數?
由於CLR的緣故,GC只能釋放託管資源,不能釋放非託管資源(數據庫連接、文件流等)
那麼該如何釋放非託管資源呢?
通常咱們會選擇爲類實現IDispose接口,寫一個Dispose方法。
讓調用者手動調用這個類的Dispose方法(或者用using語句塊來調用Dispose方法)
這是不錯的選擇,由於調用者最清楚該何時來釋放這些資源。
這個方法執行時,析構函數和垃圾收集器都尚未開始處理這個對象的釋放工做
-------------------------
有時候,咱們不想爲一個類型實現Dispose方法,
咱們想讓他自動的釋放非託管資源。那麼就要用到析構函數了。
析構函數是個很奇怪的函數,調用者沒法調用對象的析構函數,析構函數是由GC調用的。
你沒法預測析構函數什麼時候會被調用,因此儘可能不要在這裏操做可能被回收的託管資源,析構函數只用來釋放非託管資源
GC釋放包含析構函數的對象,比較麻煩(須要幹兩次才能幹掉她),
CLR會先讓析構函數執行,再收集它佔用的內存。
咱們須要手動執行垃圾收集嗎?什麼場景下這麼作?
GC什麼時候執行垃圾收集是一個很是複雜的算法(策略)
大概能夠描述成這樣:
若是GC發現上一次收集了不少對象,釋放了很大的內存,
那麼它就會盡快執行第二次回收,
若是它頻繁的回收,但釋放的內存很少,
那麼它就會減慢回收的頻率。
因此,儘可能不要調用GC.Collect()這樣會破壞GC現有的執行策略。
除非你對你的應用程序內存使用狀況很是瞭解,你知道什麼時候會產生大量的垃圾,那麼你能夠手動干預垃圾收集器的工做
我有一個大對象,我擔憂GC要過好久纔會收集他,
簡單聊一下弱引用和垃圾收集之間的關係?
假設有一個大對象,用完以後,引用關係沒有的時候(這一句更改過),這個時候GC隨時都有可能收集它,並釋放他佔用的內存
但由於是一個較大的對象,頗有可能在第3代,估計GC一時半會還不會去收集它。
這個對象已經在垃圾堆裏了,可是我還想用它,怎麼辦?怎麼從垃圾堆裏把它撈回來呢?
這個時候就用到了弱引用,來看看下面這段代碼:
var bss = new BsCtl(BrowserContainer); var vbss = new WeakReference<BsCtl>(bss); bss = null; BsCtl ok; vbss.TryGetTarget(out ok); //若是沒有進行垃圾收集OK不會爲NULL if (ok == null) { //若是已經進行了垃圾收集,就會執行這段代碼 ok = new BsCtl(BrowserContainer); }
垃圾收集隨時能夠收集bss對象,
若是收集了,就會進入if語句塊,若是沒有收集,就不會進入if語句塊,TryGetTarget(out ok)就成功把bss從垃圾堆裏撈回來了
注意:這裏只說了短弱引用,沒有說起長弱引用,我以爲長弱引用使用的場景較少(謝謝園友imfunny的提醒)
垃圾收集器的好處
不少面試官都愛問這個問題,但我歷來不問,
(其實我不多問關於垃圾收集方面的任何東西,除非應聘者本身談到這方面來)
由於我沒有很豐富的C/C++編程經驗,
若是想談垃圾收集器的好處,那麼勢必要和C/C++這樣的較低級的語言對比。
應聘者大概能夠說說,
減小內存使用不當的BUG,提高編程效率之類的問題
其餘
這篇文章參考了CLR VIA C#第三版,另外還參考了博客園一位園友的博客,但地址已經找不到了