語言特性 Go語言作為一門全新的靜態(tài)類型開發(fā)語言,與當(dāng)前的開發(fā)語言相比具備眾多令人興奮不已 的新特性。
Go語言最主要的特性:
- 自動垃圾回收
- 更豐富的內(nèi)置類型
- 函數(shù)多返回值
- 錯(cuò)誤處理
- 匿名函數(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í)行時(shí),會發(fā)現(xiàn)該進(jìn)程所占用的內(nèi)存會一直瘋長,直至占用所有系統(tǒng)內(nèi)存并導(dǎo)致程序崩潰,而如果泄露的是系 統(tǒng)資源的話,那么后果還會更加嚴(yán)重,最終很有可能導(dǎo)致系統(tǒng)崩潰。
- 手動管理內(nèi)存的另外一個(gè)問題就是由于指針的到處傳遞而無法確定何時(shí)可以釋放該指針?biāo)赶虻膬?nèi)存塊。假如代碼中某個(gè)位置釋放了內(nèi)存,而另一些地方還在使用指向這塊內(nèi)存的指針, 那么這些指針就變成了所謂的“野指針”(wild pointer)或者“懸空指針”(dangling pointer),對 這些指針進(jìn)行的任何讀寫操作都會導(dǎo)致不可預(yù)料的后果。
- 由于其杰出的效率,C和C++語言在非常長的時(shí)間內(nèi)都作為服務(wù)端系統(tǒng)的主要開發(fā)語言,比 如Apache、Nginx和MySQL等著名的服務(wù)器端軟件就是用C和C++開發(fā)的。然而,內(nèi)存和資源管 理一直是一個(gè)讓人非常抓狂的難題。服務(wù)器的崩潰十有八九就是因?yàn)椴徽_的內(nèi)存和資源管理導(dǎo)致,更討厭的是這種內(nèi)存和資源管理問題即使被發(fā)現(xiàn)了,也很難定位到具體的錯(cuò)誤地點(diǎn),導(dǎo)致無數(shù)程序員通宵達(dá)旦地調(diào)試程序。 這個(gè)問題在多年里被不同人用不同的方式來試圖解決,并誕生了一些非常著名的內(nèi)存檢查工具,比如Rational Purify、Compuware BoundsChecker和英特爾的Parallel Inspector等。從設(shè)計(jì)方法的 角度也衍生了類似于內(nèi)存引用計(jì)數(shù)之類的方法(通常被稱為“智能指針”),后續(xù)在Windows平臺 上標(biāo)準(zhǔn)化的COM出現(xiàn)的一個(gè)重要原因就是為了解決內(nèi)存管理的難題。但是事實(shí)證明,這些工具和方法雖然能夠在一定程度上輔助開發(fā)者,但并沒法讓開發(fā)者避免通宵調(diào)試這樣又苦又累的工作。
-
到目前為止,內(nèi)存泄露的最佳解決方案是在語言級別引入自動垃圾回收算法(Garbage Collection,簡稱GC)。所謂垃圾回收,即所有的內(nèi)存分配動作都會被在運(yùn)行時(shí)記錄,同時(shí)任何對 該內(nèi)存的使用也都會被記錄,然后垃圾回收器會對所有已經(jīng)分配的內(nèi)存進(jìn)行跟蹤監(jiān)測,一旦發(fā)現(xiàn) 有些內(nèi)存已經(jīng)不再被任何人使用,就階段性地回收這些沒人用的內(nèi)存。當(dāng)然,因?yàn)樾枰M量最小 化垃圾回收的性能損耗,以及降低對正常程序執(zhí)行過程的影響,現(xiàn)實(shí)中的垃圾回收算法要比這個(gè) 復(fù)雜得多,比如為對象增加年齡屬性等,但基本原理都是如此。
自動垃圾回收在C/C++社區(qū)一直作為一柄雙刃劍看待,雖然到C++0x(后命名為C++11)正 式發(fā)布時(shí),這個(gè)呼聲頗高的特性總算是被加入了,但按C++之父的說法,由于C++本身過于強(qiáng)大, 導(dǎo)致在C++中支持垃圾收集變成了一個(gè)困難的工作。假如C++支持垃圾收集,以下的代碼片段在 運(yùn)行時(shí)就會是一個(gè)嚴(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)存管理這個(gè)問題。又因?yàn)镚o語言沒有C++ 這么“強(qiáng)大”的指針計(jì)算功能,因此可以很自然地包含垃圾回收功能。因?yàn)槔厥展δ艿闹С郑?開發(fā)者無需擔(dān)心所指向的對象失效的問題,因此Go語言中不需要delete關(guān)鍵字,也不需要free() 方法來明確釋放內(nèi)存。例如,對于以上的這個(gè)C語言例子,如果使用Go語言實(shí)現(xiàn),我們就完全不 用考慮何時(shí)需要釋放之前分配的內(nèi)存的問題,系統(tǒng)會自動幫我們判斷,并在合適的時(shí)候(比如CPU 相對空閑的時(shí)候)進(jìn)行自動垃圾收集工作。
自我驗(yà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多個(gè)指針指向相同的對象。shared_ptr使用引用計(jì)數(shù),每一個(gè)shared_ptr的拷貝都指向相同的內(nèi)存。每使用他一次,內(nèi)部的引用計(jì)數(shù)加1,每析構(gòu)一次,內(nèi)部的引用計(jì)數(shù)減1,減為0時(shí),自動刪除所指向的堆內(nèi)存。shared_ptr內(nèi)部的引用計(jì)數(shù)是線程安全的,但是對象的讀取需要加鎖。
-
2. unique_ptr“唯一”擁有其所指對象,同一時(shí)刻只能有一個(gè)unique_ptr指向給定對象(通過禁止拷貝語義、只有移動語義來實(shí)現(xiàn))。相比與原始指針unique_ptr用于其RAII的特性,使得在出現(xiàn)異常的情況下,動態(tài)資源能得到釋放。unique_ptr指針本身的生命周期:從unique_ptr指針創(chuàng)建時(shí)開始,直到離開作用域。離開作用域時(shí),若其指向?qū)ο?,則將其所指對象銷毀(默認(rèn)使用delete操作符,用戶可指定其他操作)。unique_ptr指針與其所指對象的關(guān)系:在智能指針生命周期內(nèi),可以改變智能指針?biāo)笇ο?,如?chuàng)建智能指針時(shí)通過構(gòu)造函數(shù)指定、通過reset方法重新指定、通過release方法釋放所有權(quán)、通過移動語義轉(zhuǎn)移所有權(quán)。
-
3. weak_ptr是為了配合shared_ptr而引入的一種智能指針,因?yàn)樗痪哂衅胀ㄖ羔樀男袨椋瑳]有重載operator*和->,它的最大作用在于協(xié)助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。weak_ptr可以從一個(gè)shared_ptr或者另一個(gè)weak_ptr對象構(gòu)造,獲得資源的觀測權(quán)。但weak_ptr沒有共享資源,它的構(gòu)造不會引起指針引用計(jì)數(shù)的增加。使用weak_ptr的成員函數(shù)use_count()可以觀測資源的引用計(jì)數(shù),另一個(gè)成員函數(shù)expired()的功能等價(jià)于use_count()==0,但更快,表示被觀測的資源(也就是shared_ptr的管理的資源)已經(jīng)不復(fù)存在。weak_ptr可以使用一個(gè)非常重要的成員函數(shù)lock()從被觀測的shared_ptr獲得一個(gè)可用的shared_ptr對象, 從而操作資源。但當(dāng)expired()==true的時(shí)候,lock()函數(shù)將返回一個(gè)存儲空指針的shared_ptr。