C++語言特性(1)---影響性能的因素

大多數開發人員通常都有這個觀點,即彙編語言和 C 語言適合用來編寫對性能要求非常高的程序。而 C++ 語言的主要應用範圍是編寫複雜度非常高的程序,但是對性能要求不是那麼嚴格的程序。但是事實往往並非如此,很多時候,一個程序的速度在框架設計完成時大致已經確定了,而並非是因爲採用了C++語言才使其速度沒有達到預期的目標。因此當一個程序的性能需要提高時,首先需要做的是用性能檢測工具對其運行的時間分佈進行一個準確的測量,找出關鍵路徑和真正的瓶頸所在,然後針對瓶頸進行分析和優化,而不是一味盲目地將性能低劣歸咎於所採用的語言。事實上,如果框架設計不做修改,即使用C語言或者彙編語言重新改寫,也並不能保證提高總體性能。

因此當遇到性能問題時,首先檢查和反思程序的總體框架。然後用性能檢測工具對其實際運行做準確地測量,再針對瓶頸進行分析和優化,這纔是正確的思路。

但不可否認的是,確實有一些操作或者C++的一些語言特性比其他因素更容易成爲程序的瓶頸,一般公認的有如下因素。

(1)缺頁:如第四章中所述,缺頁往往意味着需要訪問外部存儲。因爲外部存儲訪問相對於訪問內存或者代碼執行,有數量級的差別。因此只要有可能,應該儘量想辦法減少缺頁。

(2)從堆中動態申請和釋放內存:如C語言中的malloc/free和C++語言中的new/delete操作非常耗時,因此要儘可能優先考慮從線程棧中獲得內存。優先考慮棧而減少從動態堆中申請內存,不僅僅是因爲在堆中開闢內存比在棧中要慢很多,而且還與"儘量減少缺頁"這一宗旨有關。當執行程序時,當前棧幀空間所在的內存頁肯定在物理內存中,因此程序代碼對其中變量的存取不會引起缺頁;相反,從堆中生成的對象,只有指向它的指針在棧上,對象本身卻是在堆中。堆一般來說不可能都在物理內存中,而且因爲堆分配內存的特性,即使兩個相鄰生成的對象,也很有可能在堆內存位置上相隔很遠。因此當訪問這兩個對象時,雖然分別指向它們指針都在棧上,但是通過這兩個指針引用它們時,很有可能會引起兩次"缺頁"。

(3)複雜對象的創建和銷燬:這往往是一個層次相當深的遞歸調用,因爲一個對象的創建往往只需要一條語句,看似很簡單。另外,編譯器生成的臨時對象因爲在程序的源代碼中看不到,更是不容易察覺,因此尤其值得警惕和關注。本章中專門有兩節分別講解對象的構造和析構,以及臨時對象。

(4)函數調用:因爲函數調用有固定的額外開銷,因此當函數體的代碼量相對較少,且該函數被非常頻繁地調用時,函數調用時的固定額外開銷容易成爲不必要的開銷。 C語言的宏和C++語言的內聯函數都是爲了在保持函數調用的模塊化特徵基礎上消除函數調用的固定額外開銷而引入的,因爲宏在提供性能優勢的同時也給開發和調試帶來了不便。在C++中更多提倡的是使用內聯函數,本章會有一節專門講解內聯函數。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章