IOS 記憶體最佳化和調試技巧

來源:互聯網
上載者:User

  基礎部分

  1: 圖片記憶體大小小結

  a: 圖片:是佔用記憶體的大戶,尤其是手機遊戲圖片資源眾多。對圖片資源在記憶體中佔用量的計算成為J2ME遊戲開發人員的經常性工作,CoCoMo來解釋一下如何計算圖片在記憶體中的佔用量:記憶體佔用量=寬*高*像素位元組數,其中像素位元組數因機型而異。

  例如一張64*64的圖片在7210上的記憶體佔用量=64*64*1.5=6144(位元組)=6K、在S60上的記憶體佔用量=64*64*2=8192 (位元組)=8K。像素位元組數因機型而異,例如 7210是4096色機型,也就是說用12位來表示一個像素,所以乘上1.5,而S60是65536色的機型,用16位來表示一個像素,所以乘上2。

  b:Xcode中使用instruments 查看圖片記憶體的問題

  如果使用的是模擬器那麼預設是小螢幕的,所以最大圖片是1024 *1024 * 4 = 4 M (1024 是圖片的寬高, 4表示的是圖片的儲存類型為4位元組的。也就是 RGBA8888)

  如果你載入了圖片那麼就是使用了4M的記憶體。如果你需要渲染那麼還需要4M的記憶體。

  載入一般都是 **load (NSString *)filename ,

  渲染一般都是 Node addChild (Node)

  2: 引用計數問題

  引用計數增加的情況 : a: alloc 對象會使得對象引用數 +1

  b:調用retain (具體細說一些執行個體如下)

  ->比如你是cocos2d使用者的會看到 addchild 會使子節點的引用計數+1

  ->CCArray 的addObject 也會使元素的引用計數+1

  總結一下就是: 凡是添加到結合中的元素或者子節點不需要再去retain ,只需要在建立的時候調用release

  減少的情況 : 調用release 使引用計數 -1(具體細說一些執行個體如下)

  -> 集合調用remove/removeChildByTag 等等變形的

  -> 建立的時候調用autorelease 。注意:如果你的對象是局部對象,而且建立的時候使用的是autorelease,

  那麼在離開方法的時候如果你沒有retain 那麼這個對象將被dealloc(引用計數-1了)

  官網的介紹:

  •

  You own any object you create by allocating memory for it or copying it.

  Related methods:alloc,allocWithZone:,copy,copyWithZone:,mutableCopy,mutableCopyWithZone:

  If you are not the creator of an object, but want to ensure it stays in memory for you to use, you can express an ownership interest in it.

  Related method:retain

  If you own an object, either by creating it or expressing an ownership interest, you are responsible for releasing it when you no longer need it.

  Related methods:release,autorelease

  Conversely, if you are not the creator of an object and have not expressed an ownership interest, you mustnotrelease it.

  3 :參考文檔

  一,IOS與圖片記憶體

  在IOS上,圖片會被自動縮放到2的N次方大小。比如一張1024*1025的圖片,佔用的記憶體與一張1024*2048的圖片是一致的。圖片佔用記憶體大小的計算的公式是;長*寬*4。這樣一張512*512佔用的記憶體就是 512*512*4 = 1M。其他尺寸以此類推。(ps:IOS上支援的最大尺寸為2048*2048)。

  ,cocos2d-x的圖片緩衝

  Cocos2d-x 在構造一個精靈的時候會使用spriteWithFile或者spriteWithSpriteFrameName等無論用哪種方式,cocos2d-x都會將這張圖片載入到緩衝中。如果是第一次載入這個圖片,那就會先將這張圖片載入到緩衝,然後從緩衝讀取。如果緩衝中已經存在,則直接從緩衝中提取,免除了載入過程。

  圖片的緩衝主要由以下兩個類來處理:CCSpriteFrameCache, CCTextureCache

  CCSpriteFrameCache載入的是一張拼接過的大圖,每一個小圖只是大圖中的一個地區,這些地區資訊都在plist檔案中儲存。用的時候只需要根據小圖的名稱就可以載入到這個地區。

  CCTextureCache 是普通的圖片緩衝,我們所有直接載入的圖片都會預設放到這個緩衝中,以提高調用效率。

  因此,每次載入一張圖片,或者通過plist載入一張拼接圖時,都會將整張圖片載入到記憶體中。如果不去釋放,那就會一直佔用著。

  三,渲染記憶體。

  不要以為,計算記憶體時,只計算載入到緩衝中的記憶體就可以了。以一張1024*1024的圖片為例。

  CCSprite *pSprite = CCSprite::spriteWithFile("a.png");

  調用上邊這行代碼以後,可以在LEAKS工具中看到,增加了大約4M的記憶體。然後接著調用

  addChild(pSprite);

  這時,記憶體又增加了4M。也就是,一張圖片,如果需要渲染的話,那它所佔用的記憶體將要X2。

  再看看通過plist載入的圖片,比如這張大圖尺寸為2048*2048。想要載入其中的一張32*32的小圖片

  CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("b.plist");

  此時記憶體增加16M (汗)

  CCSprite *pSpriteFrame = CCSprite::spriteWithSpriteFrameName("b1.png");

  b.png 大小為32*32,想著也就是增加一點點記憶體,可實際情況是增加16M記憶體。也就是只要渲染了其中的一部分,那麼整張圖片都要一起被載入。

  但是情況不是那麼的糟糕,這些已經渲染的圖片,如果再次載入的話,記憶體是不會再繼續升高的,比如又增加了100個b.plist的另一個地區,圖片記憶體還是共增加16+16 = 32M,而不會繼續上升。

  四,緩衝釋放

  如果遊戲有很多情境,在切換情境的時候可以把前一個情境的記憶體全部釋放,防止總記憶體過高.

  CCTextureCache::sharedTextureCache()->removeAllTextures();釋放到目前為止所有載入的圖片

  CCTextureCache::sharedTextureCache()->removeUnusedTextures();將引用計數為1的圖片釋放掉CCTextureCache::sharedTextureCache()->removeTexture();單獨釋放某個圖片

  CCSpriteFrameCache與 CCTextureCache 釋放的方法差不多。

  值得注意的是釋放的時機,一般在切換情境的時候釋放資源,如果從A情境切換到B情境,調用的函數順序為B::init()---->A::exit()---->B::onEnter()可如果使用了轉場效果,比如CTransitionJumpZoom::transitionWithDuration這樣的函數,則函數的調用順序變為B::init()---->B::onEnter()---->A::exit()而且第二種方式會有一瞬間將兩個情境的資源疊加在一起,如果不採取過度,很可能會因為記憶體吃緊而崩潰。

  有時強制釋放全部資源時,會使某個正在執行的動畫失去引用而彈出異常,可以調用CCActionManager::sharedManager()->removeAllActions();來解決。

  五,記憶體最佳化

  最佳化的心得就是盡量去拼接圖片,使圖片邊長儘可能的保持2的N次方並且裝的很滿。但要注意,有邏輯關係的圖片盡量打包在一張大圖裡,另外一點就是打包的時候要考慮到層的分布。因為為了渲染效率可能會用到CCSpriteBatchNode;同一個BatchNode裡的圖片都是位於一個層級的,因此必鬚根據各個圖片的層級關係,打包到不同的plist裡。有時記憶體和效率不可以兼得,只能盡量平衡了。

  六,其他

  最後附一個各代IOS裝置的記憶體限制情況

  裝置 建議記憶體 最大記憶體

  iPad2/iPhone4s/iphone4 170-180mb 512mb

  iPad/iPod touch3,4/iphone3gs 40-80mb 256mb

  iPod touch1,2/iPhone3g/iPhone1 25mb 128mb

  上述建議記憶體只是一些人自己測試的結果,可用的RAM不大於最大記憶體的一半,如果程式超過最大記憶體的一半,則可能會掛掉。

  另外在LEAKS裡查看模擬器中和真機總的記憶體,會有較大出入。在模擬器中的結果與實際更接近一些。

  七, 泄漏的情況

  我所碰到的主要記憶體泄露的方式:

  1、最常見的就是,申請了引用,然後最後忘記釋放。具體麼就是,使用OC的 alloc, retain, copy, new, C的malloc, realloc, C++的new等,然後沒有對應的release, free, delete。這是單向泄露。

  2、retain cycle,對於OC這種使用計數的方式,可能會存在retain cycle。兩個條件,一、就是A中retain了B,B又retain了A,各自給對方計數增加,這個環可以變為很多層,就是A->B, B->C, C->D, .... Z->A,當然假如中介層越多,檢測難度就越大。二、計數減少的操作是在dealloc中,而dealloc被調用則需要計數為0。 這兩個條件相加,導致計數鎖定,記憶體泄露。

  實戰演練

  如何尋找記憶體流失 ?

  一:對工具的使用來尋找

  1、首先流量分析編譯,Analyze build,查看歸類當中的memory警告。

  這個一般能發現局部變數中忘記release,或者被中途打斷release的。

  2、然後就是直接使用Instruments中的leak監測。

  申請了記憶體,然後已經沒有指向這塊記憶體的指標存在,可以認為是leak了。這個檢測一般是檢測這個狀態。

  3、通過Instruments中allocation的mark heap。

  進行不斷的重複操作,在每次情境結束後,標記記憶體。假如操作環境沒有泄露,記憶體增加應該是0。這個檢測是檢測標記點之間有哪些對象增加。另外,需要多mark幾次才會準確,不要mark兩次看到有記憶體增加就去找問題。

  Instruments中都是可以看到其中存在什麼對象,調用曆史,呼叫堆疊。這時候大致確定在那個類當中的那個對象泄露了。

  二 ,重載法。

  雖然知道了哪個類泄露了,但是有時候並不知道具體是那邊的計數出現問題。我自己的方法是,假如是自己編寫的類,那就重載retain和release方法,然後加斷點。以此來監測是什麼地方retain了這個對象,卻沒有對應釋放。

  如何修改記憶體流失呢 ?

  1、缺啥補啥。缺release的,就補release,缺free的就加個free。

  2、合理使用autorelease。對於返回給上層使用的;或者alloc對象到release中間有return等打斷操作的。建議使用autorelease。

  3、合理使用assign。retain cycle,本質就是多餘的雙向retain。打個比方就是應該確定哪個對象是根,哪一個是枝葉,枝葉不用去管理根,只需要知道根在那邊就可以了。所以把那些純粹是定位用的變數,屬性都改成assign方式,例如delegate。

  PS:

  假如對於Instruments的使用不是很清楚,可以看這個視頻 https://developer.apple.com/videos/wwdc/2010/?id=311

  遊戲中我遇到的一個非常難查的泄漏這裡貢獻出來 :

  對於cocos2d的使用者如果使用了CCMenu ,而且也重寫了CCScene中的onExsit 函數來檢測離開情境的時候的一些變化。但是忘了去調用super onExsit

  這時候CCMenu自己註冊了一個事件delegate 就無法釋放導致CCMenu一直無法釋放。當載入到了其他情境的時候事件總會不對。就是因為這個導致的

  解決辦法自然是調用super onExsit 。因為在這裡他釋放了delegate

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.