語言特性 Go語言作為一門全新的靜態(tài)類型開發(fā)語言,與當(dāng)前的開發(fā)語言相比具備眾多令人興奮不已 的新特性巧号。
Go語言最主要的特性:
- 自動垃圾回收
- 更豐富的內(nèi)置類型
- 函數(shù)多返回值
- 錯誤處理
- 匿名函數(shù)和閉包
- 類型和接口
- 并發(fā)編程
- 反射
- 語言交互性
比較有意思的是作者對自動垃圾回收精確的描述族奢,但有些描述不一定完全準(zhǔn)確:
自動垃圾回收可以先看下不支持垃圾回收的語言的資源管理方式,以下為一小段C語言代碼:
void foo() {
char* p = new char[128]; ... // 對p指向的內(nèi)存塊進(jìn)行賦值
func1(p); // 使用內(nèi)存指針
delete[] p; }
- 各種非預(yù)期的原因丹鸿,比如由于開發(fā)者的疏忽導(dǎo)致最后的delete語句沒有被調(diào)用越走,都會引發(fā) 經(jīng)典而惱人的內(nèi)存泄露問題。假如該函數(shù)被調(diào)用得非常頻繁靠欢,那么觀察該進(jìn)程執(zhí)行時廊敌,會發(fā)現(xiàn)該進(jìn)程所占用的內(nèi)存會一直瘋長,直至占用所有系統(tǒng)內(nèi)存并導(dǎo)致程序崩潰门怪,而如果泄露的是系 統(tǒng)資源的話骡澈,那么后果還會更加嚴(yán)重,最終很有可能導(dǎo)致系統(tǒng)崩潰掷空。
- 手動管理內(nèi)存的另外一個問題就是由于指針的到處傳遞而無法確定何時可以釋放該指針?biāo)赶虻膬?nèi)存塊肋殴。假如代碼中某個位置釋放了內(nèi)存,而另一些地方還在使用指向這塊內(nèi)存的指針坦弟, 那么這些指針就變成了所謂的“野指針”(wild pointer)或者“懸空指針”(dangling pointer)护锤,對 這些指針進(jìn)行的任何讀寫操作都會導(dǎo)致不可預(yù)料的后果。
- 由于其杰出的效率减拭,C和C++語言在非常長的時間內(nèi)都作為服務(wù)端系統(tǒng)的主要開發(fā)語言行瑞,比 如Apache盖文、Nginx和MySQL等著名的服務(wù)器端軟件就是用C和C++開發(fā)的持痰。然而朽缴,內(nèi)存和資源管 理一直是一個讓人非常抓狂的難題。服務(wù)器的崩潰十有八九就是因為不正確的內(nèi)存和資源管理導(dǎo)致可霎,更討厭的是這種內(nèi)存和資源管理問題即使被發(fā)現(xiàn)了魄鸦,也很難定位到具體的錯誤地點(diǎn),導(dǎo)致無數(shù)程序員通宵達(dá)旦地調(diào)試程序癣朗。 這個問題在多年里被不同人用不同的方式來試圖解決拾因,并誕生了一些非常著名的內(nèi)存檢查工具,比如Rational Purify旷余、Compuware BoundsChecker和英特爾的Parallel Inspector等绢记。從設(shè)計方法的 角度也衍生了類似于內(nèi)存引用計數(shù)之類的方法(通常被稱為“智能指針”),后續(xù)在Windows平臺 上標(biāo)準(zhǔn)化的COM出現(xiàn)的一個重要原因就是為了解決內(nèi)存管理的難題正卧。但是事實(shí)證明蠢熄,這些工具和方法雖然能夠在一定程度上輔助開發(fā)者,但并沒法讓開發(fā)者避免通宵調(diào)試這樣又苦又累的工作炉旷。
-
到目前為止签孔,內(nèi)存泄露的最佳解決方案是在語言級別引入自動垃圾回收算法(Garbage Collection叉讥,簡稱GC)。所謂垃圾回收饥追,即所有的內(nèi)存分配動作都會被在運(yùn)行時記錄图仓,同時任何對 該內(nèi)存的使用也都會被記錄,然后垃圾回收器會對所有已經(jīng)分配的內(nèi)存進(jìn)行跟蹤監(jiān)測但绕,一旦發(fā)現(xiàn) 有些內(nèi)存已經(jīng)不再被任何人使用救崔,就階段性地回收這些沒人用的內(nèi)存。當(dāng)然捏顺,因為需要盡量最小 化垃圾回收的性能損耗帚豪,以及降低對正常程序執(zhí)行過程的影響,現(xiàn)實(shí)中的垃圾回收算法要比這個 復(fù)雜得多草丧,比如為對象增加年齡屬性等,但基本原理都是如此莹桅。
自動垃圾回收在C/C++社區(qū)一直作為一柄雙刃劍看待昌执,雖然到C++0x(后命名為C++11)正 式發(fā)布時,這個呼聲頗高的特性總算是被加入了诈泼,但按C++之父的說法懂拾,由于C++本身過于強(qiáng)大, 導(dǎo)致在C++中支持垃圾收集變成了一個困難的工作铐达。假如C++支持垃圾收集岖赋,以下的代碼片段在 運(yùn)行時就會是一個嚴(yán)峻的考驗:
int* p = new int;
p += 10; // 對指針進(jìn)行了偏移,因此那塊內(nèi)存不再被引用
// …… 這里可能會發(fā)生針對這塊int內(nèi)存的垃圾收集 ……
p -= 10; // 咦瓮孙,居然又偏移到原來的位置
*p = 10; // 如果有垃圾收集唐断,這里就無法保證可以正常運(yùn)行了
微軟的C++/CLI算是用一種偏門的方式讓C++程序員們有機(jī)會品嘗一下垃圾回收功能的鮮美味道。
- 在C/C++之后出現(xiàn)的新語言杭抠,比如Java和C#等脸甘,基本上都已經(jīng)自帶自動垃圾回收功能。 Go語言作為一門新生的開發(fā)語言偏灿,當(dāng)然不能忽略內(nèi)存管理這個問題丹诀。又因為Go語言沒有C++ 這么“強(qiáng)大”的指針計算功能,因此可以很自然地包含垃圾回收功能翁垂。因為垃圾回收功能的支持铆遭, 開發(fā)者無需擔(dān)心所指向的對象失效的問題,因此Go語言中不需要delete關(guān)鍵字沿猜,也不需要free() 方法來明確釋放內(nèi)存枚荣。例如,對于以上的這個C語言例子邢疙,如果使用Go語言實(shí)現(xiàn)棍弄,我們就完全不 用考慮何時需要釋放之前分配的內(nèi)存的問題望薄,系統(tǒng)會自動幫我們判斷,并在合適的時候(比如CPU 相對空閑的時候)進(jìn)行自動垃圾收集工作呼畸。
自我驗證體會痕支,有些觀點(diǎn)不一定完全準(zhǔn)確,比如C/C++高效的指針運(yùn)算是別的語言所不具備的蛮原,但相應(yīng)的自動垃圾回收變的幾乎不可實(shí)現(xiàn)卧须,但相應(yīng)的提供了智能指針的解決方案。
智能指針在C++11版本之后提供儒陨,包含在頭文件<memory>中花嘶,shared_ptr、unique_ptr蹦漠、weak_ptr椭员。
-
1.shared_ptr多個指針指向相同的對象。shared_ptr使用引用計數(shù)笛园,每一個shared_ptr的拷貝都指向相同的內(nèi)存隘击。每使用他一次,內(nèi)部的引用計數(shù)加1研铆,每析構(gòu)一次埋同,內(nèi)部的引用計數(shù)減1,減為0時棵红,自動刪除所指向的堆內(nèi)存凶赁。shared_ptr內(nèi)部的引用計數(shù)是線程安全的,但是對象的讀取需要加鎖逆甜。
-
2. unique_ptr“唯一”擁有其所指對象虱肄,同一時刻只能有一個unique_ptr指向給定對象(通過禁止拷貝語義、只有移動語義來實(shí)現(xiàn))忆绰。相比與原始指針unique_ptr用于其RAII的特性浩峡,使得在出現(xiàn)異常的情況下,動態(tài)資源能得到釋放错敢。unique_ptr指針本身的生命周期:從unique_ptr指針創(chuàng)建時開始翰灾,直到離開作用域。離開作用域時稚茅,若其指向?qū)ο笾交矗瑒t將其所指對象銷毀(默認(rèn)使用delete操作符,用戶可指定其他操作)亚享。unique_ptr指針與其所指對象的關(guān)系:在智能指針生命周期內(nèi)咽块,可以改變智能指針?biāo)笇ο螅鐒?chuàng)建智能指針時通過構(gòu)造函數(shù)指定欺税、通過reset方法重新指定侈沪、通過release方法釋放所有權(quán)揭璃、通過移動語義轉(zhuǎn)移所有權(quán)。
-
3. weak_ptr是為了配合shared_ptr而引入的一種智能指針亭罪,因為它不具有普通指針的行為瘦馍,沒有重載operator*和->,它的最大作用在于協(xié)助shared_ptr工作,像旁觀者那樣觀測資源的使用情況应役。weak_ptr可以從一個shared_ptr或者另一個weak_ptr對象構(gòu)造情组,獲得資源的觀測權(quán)。但weak_ptr沒有共享資源箩祥,它的構(gòu)造不會引起指針引用計數(shù)的增加院崇。使用weak_ptr的成員函數(shù)use_count()可以觀測資源的引用計數(shù),另一個成員函數(shù)expired()的功能等價于use_count()==0,但更快袍祖,表示被觀測的資源(也就是shared_ptr的管理的資源)已經(jīng)不復(fù)存在底瓣。weak_ptr可以使用一個非常重要的成員函數(shù)lock()從被觀測的shared_ptr獲得一個可用的shared_ptr對象, 從而操作資源蕉陋。但當(dāng)expired()==true的時候濒持,lock()函數(shù)將返回一個存儲空指針的shared_ptr。