1、先說基本原則:

①當函數體比較小的時候, 內聯該函數可以令目標代碼更加高效. 對於存取函數以及其它函數體比較短, 性能關鍵的函數, 鼓勵使用內聯.

②一個較爲合理的經驗準則是, 不要內聯超過 10 行的函數. 謹慎對待析構函數, 析構函數往往比其表面看起來要更長, 因爲有隱含的成員和基類析構函數被調用!

2、內聯一定會增加代碼量嗎?

不一定!

因爲函數調用是需要開銷的(函數調用時的參數壓棧、棧幀開闢與銷燬、以及寄存器保存與恢復等等操作),如果說函數本身的代碼量比較小,比函數調用時做的準備工作的代碼還要小,那此時如果使用內聯的話,肯定比不使用內聯的代碼量還要小[2]。

不過如果函數的代碼量稍大,通常還是會增加代碼量的,因爲內聯函數是在編譯階段被編譯器展開在調用處的,多次調用就需要多段重複的代碼放在各個調用處。對於非內聯函數,只需要保存一份函數體的代碼,然後進行調用就好了。所以,在空間上,一般來說使用內聯函數會導致生成的可執行文件變大。

3、使用內聯函數後對於程序的性能會產生什麼影響?

首先,大家都知道現在計算機的存儲結構,這裏只考慮高速緩存到內存這一部分,從高到低,每一級的訪問時間近似以成千倍甚至更高的增加。

其次,高速緩存的大小是很小的(對於我們運行的程序來說),所以我們的數據不可能都被裝載到高速緩存中,這就引出了一個命中率的問題。在不命中的時候,就需要向更爲下層的存儲結構尋找索取目標數據,寶貴的時間也因此不斷大幅增加。正如我們前面所說,內聯使用不當會導致編譯出來的執行程序中的text段比較大,那麼相應的能夠存活在高速緩存的內容比例也就相對的減小,命中率因此降低,那就會導致程序的性能下降。即因爲存儲結構的問題,我們過度的使用內聯得到了相反的結果[1]。

對於這一點,思考角度不同,能得到不同的結果。例如,我還可以這麼想:

由於內聯後調用函數體內需要執行的代碼是相鄰的,其執行的代碼都在同一 個頁面或連續的頁面中。如果沒有內聯,執行到被調用函數時,需要跳到包含被調用函數的內存頁面中執行,而被調用函數所屬的頁面極有可能當時不在物理內存 中。這意味着,內聯後可以降低“缺頁”的幾率,知道減少“缺頁”次數的效果遠比減少一些代碼量執行的效果。另外即使被調用函數所在頁面可能也在內存中,但 是因爲與調用函數在空間上相隔甚遠,所以可能會引起“cache miss”,從而降低執行速度。因此總的來說,內聯後程序的執行時間會比沒有內聯要少。即程序的速度更快,這也是因爲內聯後代碼的空間 “locality”特性提高了[2]。

最後,反過來,內聯後,編譯器在做優化時,看到的是調用函數與被調用函數連成的一大塊代碼。即獲 得的代碼信息更多,此時它對調用函數的優化可以做得更好。

查看原文 >>
相關文章