[譯]性能概述

本文選譯自《Performance Overview》

導(dǎo)語

性能作為所有軟件產(chǎn)品的重要設(shè)計標(biāo)準(zhǔn)。如果程序運行緩慢或顯示轉(zhuǎn)圈的光標(biāo),用戶很可能對產(chǎn)品感到失望并尋求替代品。維持軟件達(dá)到一個可靠的性能水平需要你的努力,你越早考慮這些問題,就越容易找到并解決性能問題。

誰該閱讀這份文檔

性能概述是針對新入軟件性能分析領(lǐng)域開發(fā)人員的基本指導(dǎo)。本文檔提供了管理性能和定位及解決常見性能問題的一個概覽。它還向你介紹了用于定位和解決性能問題的工具和文檔。

本文結(jié)構(gòu)

本文檔包含以下章節(jié):

  • 為了性能而開發(fā)描述了影響性能的關(guān)鍵因素和在軟件中實現(xiàn)最佳性能的方法。
  • 性能開發(fā)基本建議描述了代碼中需要分析的常見區(qū)域和提供某些基礎(chǔ)性的技術(shù)。
  • 性能開發(fā)工具描述了程序中可用于性能分析的工具。
  • 做初步的性能評估帶你了解某些重要工具的基礎(chǔ)和如何使用其解決性能問題。

為了性能而開發(fā)

性能做為軟件設(shè)計時需要時常考慮的因素并變得日益緊迫。如果你等到開發(fā)周期行將結(jié)束時才去做性能優(yōu)化,這樣對于完成關(guān)鍵的改進未免有點晚了。性能在設(shè)計初期就應(yīng)當(dāng)考慮并需要在整個開發(fā)周期持續(xù)地改進。

當(dāng)然,為了完成好的性能設(shè)計,首先要理解性能到底是什么。這已章節(jié)將提供影像性能的背景知識,即OS X和iOS中這些因素的清單,以及如何對這些因素進行檢測。

何為性能?

“性能”一詞對于不同的人意味著不同的事物。所以在著手對你的應(yīng)用進行性能改進探秘之前,最好是在當(dāng)下理解這一詞條的含義。

許多人將性能等同于速度。誠然,如果程序在一秒鐘內(nèi)完成復(fù)雜的操作,你可能會認(rèn)為該程序具有良好的性能。雖然,就其本身而言速度可能是具有誤導(dǎo)性的測量。在復(fù)雜的軟件系統(tǒng)中,操作的速度并不是固定值。如果在不同條件下執(zhí)行相同的操作,需要完成該操作的時間都會有很大的不同。這是因為程序僅僅是在本地系統(tǒng)上眾多處理共享資源的進程中的一個,這些資源的使用(或濫用)會影響所有其他的進程。

下面的部分從兩個不同的方面解釋性能:資源的有效使用和性能感知。這兩個概念都會對你的應(yīng)用程序設(shè)計和實現(xiàn)產(chǎn)生重要的影響,只有了解如何結(jié)合使用它們才可以創(chuàng)造更好的整體性能。

資源的有效使用

計算機為所有運行的進程提供了有限數(shù)量的資源。在最低的層級,這些資源分為以下幾類:

  • CPU時間
  • 內(nèi)存空間
  • 磁盤空間

所有的數(shù)據(jù)都存儲在內(nèi)存中,或是在某種大容量存儲設(shè)備上,必須由中央處理器進行操作。高效的應(yīng)用程序會小心地使用所有的這些資源。下面的章節(jié)提供了關(guān)于每一種類型資源的詳細(xì)說明及其對程序的影響。

CPU時間

CPU時間由系統(tǒng)分配所以你必須盡可能地利用好這些時間。由于OS X和iOS都實現(xiàn)了對稱多處理,系統(tǒng)中的每個線程都會分配的時間片(最多10毫秒)來運行。在那段時間的末端(或者多數(shù)情況下)系統(tǒng)會回收CPU的控制并把它分配給其他線程。

在有許多活動線程的典型系統(tǒng)中,如果每個線程都用完了所分配的時間,性能將非常糟糕。這就導(dǎo)致產(chǎn)生了編寫應(yīng)用程序的最為重要的一個目標(biāo):

如果你對程序無事可做,它就不應(yīng)該消耗CPU時間。

完成這一目標(biāo)的最佳方式是使用基于事件的模型。使用現(xiàn)代化的基于事件處理的系統(tǒng),例如Cocoa以及Cocoa Touch,這意味著程序的線程只在有工作時才運行。

當(dāng)你的應(yīng)用有工作可以完成時,它應(yīng)該盡可能高效地利用時間。這意味著需要為期望處理的數(shù)據(jù)采用合適的算法。同樣意味著對于其他資源的使用,例如完成特定操作的可用的向量單元(OS X中的AltiVec和SSE)或者圖形處理器,這產(chǎn)生了以下目標(biāo):

盡可能地將工作移出CPU。

獲取如何高效地使用CPU時間,請參見基本優(yōu)化建議。獲取關(guān)于改進繪圖操作的建議,請參見繪制代碼

內(nèi)存空間

現(xiàn)代計算機硬件中的內(nèi)存正逐漸由速度較慢(但容量卻更大)的存儲器構(gòu)成。最快的存儲器是CPU的寄存器。接下來是L1級緩存,再接著是L2和L3級緩存。再接下來稍快的存儲器是內(nèi)存。最慢的存儲器是OS X磁盤上的虛擬內(nèi)存頁面組成,且必須在完成分頁后才能使用。

在理想的情況下,每一個應(yīng)用都足夠的小以能夠裝進系統(tǒng)最快的高速緩存中。不幸的是,大多數(shù)應(yīng)用程序的代碼和數(shù)據(jù)存放在內(nèi)存或者磁盤上。因此,最大程度的減少應(yīng)用程序的代碼和數(shù)據(jù)在這些較慢媒體上花費的時間顯得尤為重要,這產(chǎn)生了以下目標(biāo):

減少程序的內(nèi)存占用。

減少程序的內(nèi)存占用可以顯著地提高其性能。小的內(nèi)存占用通常有兩個優(yōu)點。首先,你的程序越小,它所占用的內(nèi)存頁就越少。較少的內(nèi)存頁,通常意味著更少的分頁。其次,代碼通常較小是作為大量優(yōu)化和更好結(jié)構(gòu)的結(jié)果。于是,只需要較少的指令來執(zhí)行既定任務(wù)以及任務(wù)的所有代碼都能聚集在同一組內(nèi)存頁中。

除了降低應(yīng)用程序的內(nèi)存占用,還應(yīng)該盡量減少應(yīng)用程序中的可寫內(nèi)存頁的占用。可寫內(nèi)存頁存儲應(yīng)用程序的全局或已分配的數(shù)據(jù)。在OS X中,如果需要的話,這樣的頁面可以被寫入磁盤,但這樣做是比較慢的。在iOS中,這些頁面的內(nèi)容必須由應(yīng)用程序本身清除,在以后可能需要應(yīng)用程序重新創(chuàng)建這些在頁面中的數(shù)據(jù)。在這兩種情況下,系統(tǒng)會努力地本應(yīng)該用于執(zhí)行應(yīng)用程序代碼的時間來釋放內(nèi)存。

獲取有關(guān)如何減少程序內(nèi)存占用的基本信息,請參見應(yīng)用內(nèi)存占用。獲取關(guān)于更加高效地使用內(nèi)存的建議,請參見內(nèi)存分配代碼

磁盤空間

文件系統(tǒng)的性能對于任何計算機都是重要的,因為幾乎所有的東西都以文件的方式保存。你的應(yīng)用程序、數(shù)據(jù),以及操作系統(tǒng)本身都存在于文件中,相較于系統(tǒng)的其他部分,從設(shè)備上加載這些文件到內(nèi)存則顯得不可思議的慢。文件系統(tǒng),無論是本地的還是基于網(wǎng)絡(luò)的,都是性能上的最大瓶頸。這就產(chǎn)生了另一個目標(biāo):

消除不必要的文件操作并在其他的信息實際需要時才進行操作。

通過消除和延遲文件的操作來解決這個性能瓶頸,對于改善應(yīng)用的整體性能非常重要。數(shù)以百萬計的處理器周期包括文件的數(shù)據(jù)請求的時間到程序?qū)嶋H找到數(shù)據(jù)的時間。如果你的程序訪問了大量的文件,它可能在接收所有請求數(shù)據(jù)之前等待數(shù)秒。

另一個重要的事情是你的應(yīng)用程序和它創(chuàng)建的任何文件可能是在網(wǎng)絡(luò)上,而不是在本地硬盤。尤其是OS X中,大量的使用了網(wǎng)絡(luò),所以你不應(yīng)該對文件的位置進行假設(shè)。

獲取關(guān)于如何改進程序中文件性能的基本信息,請參見文件訪問代碼

速度的感知

即時你為優(yōu)化性能調(diào)整了應(yīng)用程序的代碼,這完全有可能讓你應(yīng)用的行為在用戶面前表現(xiàn)得緩慢。這樣的問題是不可避免的:如果你有大量工作要完成,你就需要CPU時間和資源來完成相關(guān)工作。你唯一可以做的就是讓應(yīng)用程序來表現(xiàn)速度,這形成了下面的目標(biāo):

讓你的程序響應(yīng)用戶。

對于用戶來講響應(yīng)能力通常比絕對的速度更加重要。只要程序能夠及時地響應(yīng)命令,用戶才會愿意接受任務(wù)需要更長時間完成的事實。速度的感知是讓用戶在程序后臺處理數(shù)據(jù)時能夠繼續(xù)操作。提高應(yīng)用中并發(fā)任務(wù)執(zhí)行數(shù)量會是使其響應(yīng)用戶的絕好辦法。并發(fā)通常使用GCD或者線程來實現(xiàn)。當(dāng)你的應(yīng)用主線程響應(yīng)用戶時,分發(fā)隊列或者后臺線程則執(zhí)行計算或者耗時的任務(wù)處理。

另一種讓你的應(yīng)用更快的常規(guī)方式是改進其啟動時間。一個應(yīng)用程序花費一秒或兩秒來啟動都顯得浪費了。在那個時間段,它沒有必要去響應(yīng)用戶及去加載不是立即需要的(或是根本不使用的)資源,這完全就是浪費。

獲取有關(guān)改進啟動時間的信息,請參見啟動時初始化代碼。獲取如何改進程序感知性能的信息,請參見利用性能感知

性能跟蹤

保證高性能的唯一方式是在產(chǎn)品的整個開發(fā)過程中包含性能指標(biāo)并按照指標(biāo)來對產(chǎn)品進行測量。高性能不是你在開發(fā)周期行將結(jié)束時移植到代碼中的功能,它與整個開發(fā)周期密切相關(guān)。在編寫代碼時,清楚代碼對程序整體性能所產(chǎn)生多大的影響非常重要。如果你盡早地檢測到性能問題,你就很有機會在為時已晚之前修復(fù)它。

確定你已經(jīng)完成或者超過預(yù)定目標(biāo)的方法就是收集數(shù)據(jù)。蘋果提供了多個工具來監(jiān)測和分析程序的性能。你也可以直接在你的代碼中創(chuàng)建測量工具來幫助自動化地收集數(shù)據(jù)。不管你使用何種方法,你都需要定期體驗這些工具并分析其結(jié)果。

建立性能基線

你需要做的第一件事就是決定一組需要測定的指標(biāo)的性能基線。選擇對你的用戶最重要的任務(wù)并定義一系列的執(zhí)行限制來執(zhí)行任務(wù)。例如,你也許希望應(yīng)用程序在1秒內(nèi)加載和啟動它的初始窗口,或者你想要保持總的內(nèi)存使用在一個既定的目標(biāo)范圍內(nèi)。

被你選來評測的功能應(yīng)該能反應(yīng)用戶的需求。你的市場部門應(yīng)該能夠幫助你找到一系列和用戶相關(guān)的任務(wù)。如果你有一個既定的產(chǎn)品,請和你的用戶交流并找出他們認(rèn)為慢的以及可以改進的功能作為你計劃更新的部分。

一旦你有了想要追蹤的任務(wù)列表,你需要為每一個任務(wù)設(shè)定性能指標(biāo)。對于已經(jīng)存在的產(chǎn)品,你可以簡單地在之前版本的基礎(chǔ)上改進性能。你同樣也可以試著去測量競品的性能并設(shè)定達(dá)到或超過它性能的指標(biāo)。如果你有一個新產(chǎn)品,你可能不得不體驗大量的產(chǎn)品來找到合適的值。或者,你想要建立激進的基線值來試圖盡可能的接近那些產(chǎn)品。

正如其他性能指標(biāo)一樣,一致性非常重要。建立基線指標(biāo)的過程應(yīng)該包括你收集這些指標(biāo)的系統(tǒng)信息。記錄系統(tǒng)的硬件和軟件配置,并在同一個配置上運行測試。嘗試使用盡可能低的硬件配置來建立你的基線。在一臺快速機器上的測量可能會導(dǎo)致你相信軟件執(zhí)行得很好,但許多用戶會在較慢處理器和更少內(nèi)存的計算機上運行軟件。

盡早測量并經(jīng)常測量

性能數(shù)據(jù)不是你收集一次就希望在應(yīng)用中找到所有的性能瓶頸。如果你長時間維護著應(yīng)用的性能,就越容易找到問題。維護歷史使得容易觀察應(yīng)用的性能是提升了還是下降了。如果下降了,你可以在產(chǎn)品發(fā)布前采取措施來解決問題。

另一個需要時常測量性能的原因是你可以關(guān)聯(lián)代碼與測試結(jié)果。如果性能在特定的里程碑下降了,你可以復(fù)查那個階段的代碼并且試圖從中找到原因。同樣的,如果性能提升了,你可以使用近期的代碼作為好的編程實踐模型并鼓勵你的團隊使用相同的技術(shù)。

當(dāng)你完成部分程序的部分功能時就應(yīng)該著手做性能的測量。當(dāng)新功能完成添加時,你可以為這些新的功能進行測量。將一套自動診斷程序引入你的程序,這使得團隊中的成員能夠更加容易地立即查看到結(jié)果。有了隨時可用的信息將使他們更方便地在檢查代碼之前解決性能問題。

分析結(jié)果

收集數(shù)據(jù)是定位性能瓶頸最為重要的步驟。但是當(dāng)你有了數(shù)據(jù),如何使用它找到問題同樣重要。分析性能數(shù)據(jù)不是簡單地看輸出結(jié)果就能夠立即找到問題的。你也許幸運地快速找到了問題,但是某些微妙的問題需要更加細(xì)心的分析才能發(fā)現(xiàn)。

幫助分析結(jié)果的一種方法是將其繪制成圖形。可視化的性能數(shù)據(jù)可以幫助你查看趨勢,這比數(shù)據(jù)在電子表格中或者基于文本的媒介中來得更快。例如,你可以繪制完成一個單獨操作的時間對于特定的版本,以確定性能在個版本間是提升還是下降。在相同里程碑下繪制多個數(shù)據(jù)集也能夠揭示性能趨勢,并提供為什么性能增加或減少的洞察力。

分析更高級的算法

當(dāng)你分析性能數(shù)據(jù)時,請對問題所在的抽象層次保持一個開發(fā)的思維。假設(shè)你的數(shù)據(jù)暗示一個特定的函數(shù)內(nèi)花費了很多時間。這有可能說明函數(shù)中的代碼需要優(yōu)化以便使其執(zhí)行更快,但這是造成問題的真正原因嗎?再次運行你的程序,但這次檢查該函數(shù)被調(diào)用的次數(shù)。如果這個函數(shù)調(diào)用了一百萬次,問題可能發(fā)生最初調(diào)用它的更高級別的算法中。如果函數(shù)被調(diào)用一次,那么問題的所在就是這函數(shù)本身。

注意:Instruments是一個分析代碼運行時行為的強大工具。Instruments可以為你記錄多個指標(biāo)并依此顯示它們,使得更加容易查看趨勢。Instruments的數(shù)據(jù)挖掘能力是另一種快速地在更高級別算法中定位問題的好方法。獲取更多關(guān)于Instrument及其他蘋果提供的相關(guān)工具的信息,請參見性能工具

在分析數(shù)據(jù)時,你需要了解和考慮到性能工具本身有一定的局限性。例如,采樣程序可能會采集應(yīng)用程序花費了大量時間的地方,但你應(yīng)該明白這些工具得出眾多結(jié)論之前如何收集數(shù)據(jù)。采樣工具并不跟蹤每一個函數(shù)調(diào)用。相反,它們提供了基于在固定的時間間隔采樣的程序的統(tǒng)計分析。使用這些工具的輸出作為指南,但確保將你記錄的其他數(shù)據(jù)與之關(guān)聯(lián)。

其他分析技術(shù)

如果你對某個性能問題的真正原因有疑問,請避免對問題的原因做出假設(shè)。相反,通過關(guān)注數(shù)據(jù)收集工作的相關(guān)代碼來改進你的分析。嘗試使用不同的工具來收集新的信息。不同的工具可能提供一個揭示了更多的實際問題的獨特視角。

一些額外可以用來分析程序的方法如下:

  • 在調(diào)試器中查看代碼。在調(diào)試器中走查代碼可以揭示導(dǎo)致代碼的速度減慢的邏輯錯誤。
  • 為代碼添加有代碼執(zhí)行的相關(guān)的日志輸出的斷點。添加斷點追蹤初始化代碼的例子,請參見啟動時初始化代碼
  • 嘗試編碼時使用解決問題的替代方案并看看它們釋放遭遇類似問題。

性能開發(fā)基本建議

本章為如何優(yōu)化你的程序提供了實際建議。它提供了你應(yīng)該使用性能工具監(jiān)控的區(qū)域的建議,也提供了一系列改善性能的實際建議。

常見區(qū)域監(jiān)測

許多性能問題可以在程序中的特定部位被追蹤到。當(dāng)你設(shè)計和實現(xiàn)你的代碼時,你應(yīng)該監(jiān)視那些區(qū)域以確保它們滿足你設(shè)定的性能目標(biāo)。

程序的關(guān)鍵任務(wù)代碼

當(dāng)你設(shè)計你的程序時,考慮用戶使用最多的任務(wù)或工作流。在實現(xiàn)階段,確保監(jiān)視那些任務(wù)的代碼并保證它們的性能不低于預(yù)期水平。如果遇到了性能問題,你應(yīng)該立即采取措施來修復(fù)這些問題。

程序的關(guān)鍵任務(wù)在各個程序之間各有不同。例如,一個文字處理工具可能需要在文本輸入和顯示上表現(xiàn)得很快,然而一個文件管理程序卻需要在硬盤上掃描文件及目錄時很快。這取決于你決定哪一項任務(wù)是用戶最希望實現(xiàn)的。

繪制代碼

大多數(shù)程序都完成一定數(shù)量的圖形繪制工作。如果你對程序只使用標(biāo)準(zhǔn)的窗口和控制器,那你也許不需要太過于擔(dān)心圖形繪制的性能。然而,如果你做任何自定義的繪制操作,你需要監(jiān)視你對圖形繪制代碼并確保其運行在可以接受的水平。特別的,如果你支持下面的功能,你需要探究優(yōu)化圖形繪制代碼的方法。

  • 自動縮放。
  • 自定義的視圖繪制代碼,尤其是部分視圖的更新而不是整個視圖。
  • 文本的圖形化。
  • 完全的透明視圖。
啟動時初始化代碼

啟動時間作為初始化程序數(shù)據(jù)結(jié)構(gòu)以及應(yīng)用準(zhǔn)備接收用戶輸入的時機。然而,許多程序在啟動時完成了超過其所需的大量工作。在大多數(shù)情況下,啟動時執(zhí)行的任務(wù)可以被推遲到應(yīng)用已經(jīng)顯示界面以及開始處理事件的時候。這樣的延遲會讓你的用戶感覺應(yīng)用很快,這會留下一個好的印象。

對于運行在OS X 10.3.3及其早期版本上的應(yīng)用程序,另一種改善啟動時間的方式是預(yù)綁定應(yīng)用。預(yù)綁定涉及到庫地址范圍的預(yù)計算并將這些值存儲到應(yīng)用的二進制文件中。這一步驟消除了啟動時動態(tài)加載器(dyld)對于地址范圍的計算。在OS X 10.3.4及其以后版本中dyld的預(yù)綁定改進將不再必須。同樣的,iOS也不需要預(yù)綁定。

文件訪問代碼

文件系統(tǒng)是講信息傳入到內(nèi)存和CPU中的重要部分。在訪問一個文件的時候,會執(zhí)行數(shù)以千萬計的指令。因此,檢查你的程序使用文件的方式并確保這些文件確實是必要的且使用得當(dāng)顯得尤為必要。

盡量減少使用文件的數(shù)量是提高文件相關(guān)性能的一種方法。當(dāng)你訪問文件時,頭腦中要記住以下幾點:

  • 了解系統(tǒng)如何緩存文件數(shù)據(jù),并知道如何優(yōu)化這些緩存的使用。避免自己緩存數(shù)據(jù)除非你打算不止一次使用它。
  • 盡可能順序地讀寫數(shù)據(jù)。在一個文件中跳躍需要花去額外的時間去尋找新的位置。
  • 盡可能從文件中讀取稍大的數(shù)據(jù)塊,記住一次性讀取過多的數(shù)據(jù)可能會導(dǎo)致不同的問題。例如,讀取一個32 MB字節(jié)文件的全部內(nèi)容可能在操作完成之前觸發(fā)這些內(nèi)容的分頁。
  • 避免非必要地關(guān)閉和重新打開文件。如果在允許緩存的情況下,這樣做可能造成即使在數(shù)據(jù)不改變的情況下緩存等待刷新。
應(yīng)用內(nèi)存占用

代碼的容量大小可以對系統(tǒng)的性能產(chǎn)生巨大的影響。程序使用的內(nèi)存頁面越多,系統(tǒng)及其他程序的可用內(nèi)存將會更少。內(nèi)存壓力會實際地造成分頁以及整個系統(tǒng)運行放緩。

管理代碼的內(nèi)存占用主要關(guān)乎于代碼和數(shù)據(jù)結(jié)構(gòu)的組織。你需要在內(nèi)存中擁有正確的區(qū)段以及不會造成任何的內(nèi)存分頁和不必要的讀取。造成內(nèi)存的大量占用有以下原因:

  • 代碼中包含未使用的代碼。編譯器通常會按照編譯模塊來組織代碼,這并不總是最好的技術(shù)。基于代碼的功能來組織代碼模塊會是更好的選擇。
  • 靜態(tài)或常量數(shù)據(jù)存儲在可寫內(nèi)存頁。在內(nèi)存分頁時,數(shù)據(jù)會被不必要地寫入磁盤。盡其所能地將這些數(shù)據(jù)移到不可寫的內(nèi)存頁以便能夠快速地銷毀。
  • 程序?qū)С龆嘤趯嶋H需要的符號文件。符號文件會占用空間并僅被應(yīng)用中需要調(diào)用的外部模塊代碼使用。移除任何不在外部使用的符號文件。
  • 代碼未被編譯器和鏈接器正確優(yōu)化。確保嘗試編譯器的優(yōu)化設(shè)置并觀察哪一個對應(yīng)用效果最好。
  • 程序中引入太多的框架。只加載程序中實際使用的框架。
內(nèi)存分配代碼

程序會分配內(nèi)存來存儲固定的及臨時的數(shù)據(jù)結(jié)構(gòu)。每次內(nèi)存的分配都與CPU及內(nèi)存的消耗相關(guān)聯(lián)。了解程序何時分配內(nèi)存以及內(nèi)存如何使用將幫助你降低上述的性能消耗。

了解程序中內(nèi)存的用處可以幫助你決定減少內(nèi)存使用的方法。你可以使用可用的性能工具在造成大量內(nèi)存分頁之前來找出自動釋放的Objective-C對象是否被釋放掉。你也可以使用這些工具來找到由代碼缺陷造成的內(nèi)存泄漏。觀察調(diào)用malloc的次數(shù)也許可以找出你可以重用的內(nèi)存塊而不是創(chuàng)建新的內(nèi)存空間。

一個內(nèi)存分配的重要法則是保持“懶惰”。延遲內(nèi)存的分配直到你真正地使用這部分內(nèi)存時。獲取更多延遲內(nèi)存分配的信息,請參見保持懶惰

獲取更多優(yōu)化內(nèi)存分配的信息,請參見《Memory Usage Performance Guidelines》

基本優(yōu)化建議

在你開始實現(xiàn)新的程序之前,有幾個你需要考慮的性能強化的點。盡管你不會在所有情況下利用好全部的優(yōu)化,但你至少應(yīng)該在設(shè)計階段考慮它們。

保持懶惰

一個改善應(yīng)用性能的簡單方式就是保證應(yīng)用不去做任何不必要的工作。應(yīng)用程序的每一時刻都應(yīng)當(dāng)被用來響應(yīng)用戶的當(dāng)前請求,而不是預(yù)測將來的請求。如果你不是立即需要某個資源,比如包含屬性窗口的nib文件,那就不要加載它。類似的行為會耗費時間來執(zhí)行,因為它訪問了文件系統(tǒng),并且如果用戶并沒有打開這個屬性窗口,加載nib文件的過程就是在浪費時間。

需要遵循的基本法則就是等待用戶向你的應(yīng)用程序請求,然后使用必須資源來滿足其請求。只有在可測量的對性能有益的情況下才去緩存數(shù)據(jù)。基于應(yīng)用程序會變快的假設(shè)去提前做緩存事實上會在低內(nèi)存情況下反而降低性能。在這種情況下,你緩存的數(shù)據(jù)在其使用前也許會被交換到磁盤上。如此,之前緩存數(shù)據(jù)所得到的任何好處都變成了性能的損失,因為這些數(shù)據(jù)必須在試用期兩次從磁盤上讀取。如果你真的想要緩存數(shù)據(jù),請在完成一次操作之后進行。

其他一些保持“懶惰”的注意事項如下:

  • 延遲內(nèi)存的分配直到實際使用該部分內(nèi)存時。
  • 不要零初始化(zero-initialize)內(nèi)存塊。調(diào)用calloc函數(shù)來完成。
  • 給系統(tǒng)懶加載代碼的機會。配置和組織你的代碼以便系統(tǒng)只加載當(dāng)前操作所需的代碼。
  • 延遲讀取文件的內(nèi)容直到實際使用這些信息的時候。
利用性能感知

在多數(shù)情況下性能的預(yù)估和實際性能同樣有效。許多程序的任務(wù)可以在后臺執(zhí)行,使用分布隊列(dispatch queue)或者空轉(zhuǎn)時間(idle time)。這樣做可以讓應(yīng)用的主線程去自由地處理同用戶的交互并使用戶感覺程序界面更具響應(yīng)性。當(dāng)你設(shè)計你的程序時,考慮哪些任務(wù)可以有效地移到后臺去。例如說,如果你的程序需要掃描一些文件或者做長度的統(tǒng)計,請使用分布隊列來做。

另一個提高性能感知能力的方法是讓你的應(yīng)用快速啟動。在啟動時,延遲任何不立即用于應(yīng)用程序界面展示的任務(wù)。例如,延遲創(chuàng)建大量的數(shù)據(jù)直到應(yīng)用程序完成啟動后并將其顯示在主窗口。如果你的主窗口顯示的某些數(shù)據(jù)需要在啟動時計算或者獲取,在窗口上顯示一個進度指示器或者其他的狀態(tài)信息來提示數(shù)據(jù)正在被加載。對于那些使用插件的應(yīng)用,避免加載插件直到代碼真正需要插件時。

使用基于事件的處理

所有現(xiàn)代的Mac應(yīng)用都應(yīng)該使用Cocoa事件系統(tǒng)或者Carbon事件管理器。(同樣的,iPhone應(yīng)用必須使用由UIKit框架提供的基于觸摸的事件系統(tǒng)。)你的應(yīng)用程序絕不應(yīng)該向系統(tǒng)輪詢事件。這樣做相當(dāng)?shù)氐托АJ聦嵣希?dāng)沒有事件處理時,輪詢代碼百分之百地是浪費CPU時間。現(xiàn)代化得基于事件的API都被設(shè)計成能提供以下優(yōu)點:

  • 它們使你的應(yīng)用程序?qū)τ脩舾唔憫?yīng)性。
  • 它們降低了應(yīng)用程序的CPU消耗。
  • 它們最小化了應(yīng)用的工作集-在任何時間加載進內(nèi)存的代碼頁數(shù)量。
  • 它們使得系統(tǒng)持續(xù)地管理電源(省電)。

包括用戶的事件,你同樣應(yīng)該避免去輪詢。OS X和iOS中的線程會使用run loop來提供對定時器、網(wǎng)絡(luò)事件以及其他收入數(shù)據(jù)的按需響應(yīng)。許多框架同樣會使用針對特殊任務(wù)的異步編程模型,并在任務(wù)完成時通知指定的回調(diào)函數(shù)或方法。在OS X 10.6及其以后版本中,分發(fā)源(dispatch sources)同樣提供了異步接收事件并在分布隊列上執(zhí)行的功能。

改進任務(wù)的并發(fā)能力

在多核計算機上,并發(fā)是另一種同時改進程序的感知性能和實際性能的方式。一個可以同時執(zhí)行多個任務(wù)的程序可以并行地在多核計算機執(zhí)行這些任務(wù)。甚至當(dāng)計算機只有一個核心時,可以將你的代碼分解為多個部分且異步的任務(wù),使之快速且正確地執(zhí)行。特別地,你應(yīng)該在分布隊列上執(zhí)行自定義的任務(wù)并讓你的主線程有時間主要去處理用戶事件以及更新用戶界面。

在你開始添加并發(fā)支持前,請確保你的程序如何正確地實現(xiàn)任務(wù)的完成。將你的代碼分解成不同的任務(wù)需要考慮到程序的數(shù)據(jù)結(jié)構(gòu)及代碼路徑。執(zhí)行共享數(shù)據(jù)的任務(wù)可能需要在串行的分布隊列上同步地訪問這些數(shù)據(jù)。

獲取更多在應(yīng)用如何實現(xiàn)并發(fā)的信息,請參見《Concurrency Programming Guide》

使用Accelerate Framework

如果你的應(yīng)用程序執(zhí)行大量的數(shù)學(xué)運算,你應(yīng)當(dāng)考慮使用Accelerate Framework(Accelerate.framework)來加速這些運算。Accelerate Framework利用了處理器中的任何可用向量單元比如Intel x86的SSE擴展)來執(zhí)行并行的多重運算。通過該框架編碼,而不是直接使用這些向量單元,可以避免為每個平臺架構(gòu)單獨單獨的代碼。Accelerate Framework在所有OS X支持的架構(gòu)中得到了高度的優(yōu)化。

類似Instruments 的工具可以幫助你找到程序中能受益于Accelerate Framework框架的部分。關(guān)于更多如何使用這些工具的信息,請參見性能工具

使應(yīng)用現(xiàn)代化

如果你的程序最初被設(shè)計運行在舊版本的Mac OS上,你應(yīng)該更新你的代碼以支持OS X。尤其,你應(yīng)該避免使用舊的技術(shù),如Carbon或QuickDraw類似的傳統(tǒng)技術(shù)。相反的,你應(yīng)該使用Cocoa或Cocoa Touch來構(gòu)建應(yīng)用。同時你需要更新二進制形式到Mach-O。Mach-O格式僅支持基于Intel的Macintosh和基于iOS的設(shè)備。

獲取iOS中可用技術(shù)列表,請參見《iOS Technology Overview》

性能工具

有幾個用于性能數(shù)據(jù)收集的圖形工具和命令行工具。一些工具和Xcode同時安裝。其他的可用工具可以從蘋果開發(fā)者網(wǎng)站下載。

關(guān)鍵應(yīng)用

盡管Xcode自帶多個收集性能數(shù)據(jù)的工具,但這里只有少數(shù)你會經(jīng)常用到。

Instruments

Instruments由一系列提供圖形界面的高性能分析工具組成,這些工具為你的應(yīng)用在運行時的行為提供前所未有的信息。并非某一時刻只顯示你的程序的一個方面,你可以使用多個Instruments工具來配置每一次分析會話,而每一中工具都收集了特定性能的數(shù)據(jù)。所有Instruments工具的數(shù)據(jù)都會并排顯示,這使得關(guān)聯(lián)數(shù)據(jù)到某一個工具和檢測應(yīng)用行為趨勢更加容易。

你可以使用Instruments工具收集如下類型的數(shù)據(jù):

  • 基于Core Data的應(yīng)用程序性能。
  • 文件系統(tǒng)讀、寫及其他操作。
  • 垃圾回收代碼的相關(guān)統(tǒng)計。
  • 圖形操作和性能相關(guān)的信息。
  • 關(guān)于對象及內(nèi)存分配的統(tǒng)計。
  • 內(nèi)存泄漏信息。
  • 應(yīng)用程序運行時統(tǒng)計采樣。
  • 關(guān)于進程和系統(tǒng)級活動的信息。
  • 關(guān)于Java線程活動的信息。
  • 關(guān)于Cocoa分發(fā)的事件信息。

獲取如何快速使用Instruments的方法,請參見使用Instruments。欲了解詳細(xì)信息,請參見《Instruments User Guide》

分析工具

Instruments不僅是收集應(yīng)用性能數(shù)據(jù)的分析工具。一些分析工具還面向?qū)ふ姨囟愋偷男阅軉栴}。表3-1列出了Xcode中以及安裝的和可供下載的分析工具。

表3-1 分析工具

工具 描述
OpenGL Driver Monitor 收集GPU相關(guān)的性能數(shù)據(jù),包括顯存相關(guān)的數(shù)據(jù)、視頻總線交通以及硬件間的stall(譯者注:stall是停止運轉(zhuǎn)的意思,發(fā)生在當(dāng)CPU執(zhí)行時,所需要的數(shù)據(jù)卻不在寄存器或緩存中,需要去裝載內(nèi)存的數(shù)據(jù),這期間有一個等待,這里叫做stall。)你可以使用這些信息來找到OpenGL應(yīng)用中造成偶然 地變慢的原因。該工具作為Xcode中圖形工具的一部分,也可以在蘋果開發(fā)者網(wǎng)站下載
OpenGL Profiler 為你的OpenGL應(yīng)用創(chuàng)建運行時文件。你可以查看函數(shù)統(tǒng)計和應(yīng)用中OpenGL的調(diào)用棧歷史。該工具作為Xcode中圖形工具的一部分,也可以在蘋果開發(fā)者網(wǎng)站下載
heap 列出指定進程中所有堆內(nèi)存malloc的區(qū)域。該工具安裝在“/usr/bin/”目錄下。
leaks 在進程的內(nèi)存區(qū)間中搜尋所有已分配卻為被引用的內(nèi)存塊。該工具安裝在“/usr/bin/”目錄下。
vmmap 顯示分配給指定進程的虛擬內(nèi)存區(qū)域。你可以使用該工具來分析進程的內(nèi)存使用。該工具安裝在“/usr/bin/”目錄下。

檢測工具

檢測工具作為自動收集數(shù)據(jù)的被動工具。為使用這些工具,請在運轉(zhuǎn)程序功能的時候同時保持這些工具運行。然后,你就可以分析這些工具產(chǎn)生的數(shù)據(jù)以更好地理解你的程序性能特征。某些程序可能會一直運行。其他大多數(shù)的程序會在收集完性能數(shù)據(jù)后終止運行。表3-2列舉了OS X中的和可供下載的檢測工具。

表3-2 檢測工具

工具 描述
Activity Monitor 顯示當(dāng)前活動進程常用的內(nèi)存使用和CPU使用相關(guān)的統(tǒng)計數(shù)據(jù)。你同樣可以從當(dāng)前應(yīng)用的進程進行采樣。該工具提供的信息和top工具類似。該工具安裝在“/Applications/Utilities/”目錄下。
Quartz Debug 顯示被重繪屏幕的實時更新。你可以使用該工具來分析你的繪圖行為。該工具作為Xcode中圖形工具的一部分,也可以在蘋果開發(fā)者網(wǎng)站下載
fs_usage 當(dāng)生成頁面故障及調(diào)用文件系統(tǒng)函數(shù)時,顯示正在進行的文件系統(tǒng)活動列表。你可以使用該工具來理解程序的文件訪問模式。該工具安裝在“/usr/bin/”目錄下。
sc_usage 顯示正在進行的系統(tǒng)調(diào)用和頁面故障統(tǒng)計數(shù)據(jù)。該工具安裝在“/usr/bin/”目錄下。
top 顯示當(dāng)前活動進程常用的內(nèi)存使用和CPU使用相關(guān)的統(tǒng)計數(shù)據(jù)。該工具會動態(tài)更新信息,以便在運行時看到趨勢。該工具安裝在“/usr/bin/”目錄下。

硬件分析工具

CHUD工具包括一些OS X中用于硬件及低等級軟件分析的補充工具。(這些工具不支持iOS。)表3-3列舉了這些工具中的一部分,也可以在蘋果開發(fā)者網(wǎng)站下載

表3-3 CHUD工具

名稱 描述
Reggie SE 讓你檢查并修改CPU和PCI的配置。
acid 分析TT6E指令追蹤和細(xì)節(jié)分析的命令行工具。你可以使用該工具來檢測隊列中的錯誤指令,如操作數(shù)未對齊,數(shù)據(jù)依賴等待及加載溢出。
simg4 Motorola 7400 處理器上的精確累加模擬器的命令行工具。(譯者注:不解釋了,OS X 10.5及更早版本可用)
simg5 IBM 970 處理器上的精確累加模擬器的命令行工具。(譯者注:不解釋了,OS X 10.5及更早版本可用)

其他命令行工具

表3-4列舉了OS X中你可以用來檢測和分析性能的其他命令行工具。(這些工具在iOS中不可用。)這些工具全部位于“/usr/bin/”目錄下且必須以命令行方式運行。大多數(shù)工具隨Xcode工具安裝。獲取更多有關(guān)這些工具的信息,請參見OS X的man幫助頁。

表3-4 命令行工具

名稱 描述
atos 在正在運行的可執(zhí)行文件中,將符號名稱和該符號的數(shù)字地址之間的轉(zhuǎn)換。
c2ph 根據(jù)對象文件中成員的偏移值顯示其C結(jié)構(gòu)。
gprof 基于對程序執(zhí)行分析來創(chuàng)建執(zhí)行配置文件。
malloc_history 顯示指定進程malloc的行為歷史。
nm 顯示一個或多個對象文件的符號表信息。
otool 以可讀性更高的方式顯示Mach-O執(zhí)行文件的內(nèi)容。
pagestuff 顯示Mach-O執(zhí)行文件的邏輯頁信息。
pstruct 根據(jù)對象文件中成員的偏移值解析并顯示其C結(jié)構(gòu)。
sample 基于對程序執(zhí)行分析來創(chuàng)建一個執(zhí)行配置文件。
vm_stat 顯示Mach的虛擬內(nèi)存統(tǒng)計數(shù)據(jù),包括活動的、非活動的、線性的(譯者注:線性指一定時間內(nèi)不能被交換的存儲區(qū)域)以及空閑的內(nèi)存頁統(tǒng)計。該工具同樣顯示頁面故障和其他活動信息。

初步性能評估

以下內(nèi)容由于可讀價值不高,譯者并不會進行翻譯。對于下面的一些工具和命令的使用,如top命令,可以在終端中使用man top命令來查看幫助文檔;Instruments的使用,可以參考《Instruments User Guide》;Quartz Debug已經(jīng)不在Xcode工具中提供,需要去單獨下載Graphics Tools才能使用。

使用top

使用Instruments

使用Quartz調(diào)試

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內(nèi)容