天天看點

20160814Object-C記憶體管理二

我在開發的過程中,出現過記憶體占用越來越大,如何解決此類問題發生,方式方法很多,可以嘗試"以自動釋放池降低記憶體峰值"的方式。

自動釋放池:

釋放對象有兩種方式,一是調用release,另一種是調用autorelease。一般情況下無需擔心自動釋放池建立的問題,系統會自動建立,比如,主線程或者是GCD會預設都有自動釋放池的建立,每次執行"事件循環"時,就會将其清空。

舉個例子:

NSArray *databaseRecords = /*....*/;
    NSMutableArray *people = [NSMutableArray array];
    for (NSDictionary *record databaseRecords) {
        SWPeople *person = [[SWPeople alloc] initWithRecord:record];
        [people addObject:person];
    }
           

如果讀取資料庫的資料很大,比如100000條,或者1000000000條,其中person這種臨時的對象會越來越多,要等待系統稍後,就是進入下一個事件循環才能将其回收,是以,應用的記憶體會持續上升,是以面對這種情況,當循環的長度無法知道的時候,我們自己可以建立一個自動釋放池,而不依賴與主線程的自動釋放池。可以調整為下面的代碼

NSArray *databaseRecords = /*....*/;
    NSMutableArray *people = [NSMutableArray array];
    for (NSDictionary *record databaseRecords) {
        @autoreleasepool {
            SWPeople *person = [[SWPeople alloc] initWithRecord:record];
            [people addObject:person];
        }
    }
           

如此一來,應用程式在執行循環中的記憶體峰值就會降低。自動釋放池就像"棧"一樣,建立好的對象壓入棧中,釋放對象從棧中彈出。在對象執行自動釋放操作,相當于将其放入棧頂的那個池中。

用"僵屍對象"(Zombie Object)調試記憶體管理問題:

什麼是僵屍對象:過渡釋放的對象,所占用的對象已經被回收的對象。

對于記憶體管理的問題,以前我使用過Xcode Instruments 查找問題,現在也可以嘗試使用僵屍對象查找問題。Xcode--->Scheme--->Diagnostics--->Enable Zombie Object 勾選。

正常情況下向已回收的對象發送消息時靈時不靈,具體要看該對象所占記憶體有沒有被覆寫。cocoa提供了僵屍對象(Zombie Object)這個功能,簡單的說:啟用該調試功能後,運作時會将所有已回收的執行個體轉化為特殊的“僵屍對象”,而不會真正回收它們。這種對象在核心記憶體無法重用,是以不可能遭到覆寫。僵屍對象收到消息後會抛出異常,其中說明了發送來的消息,并描述了回收之前的對象。(摘某部落格)

僵屍對象的工作原理是什麼,她的實作代碼深深植于OC的運作其程式庫、Foundation、CoreFoundation中,系統在回收對象的時候,将對象轉化為僵屍對象,就是不可能遭到腹寫,而不徹底回收。

其中有個重要的類,是類不是對象,_NSZombie_Class,這個類是在運作期産生的,是從_NSZombie的模闆中複制出來的,她是用來充當标記的。使對象成為僵屍對象。

系統會修改對象的isa指針,令其指向特殊的僵屍類,進而使該對象成為僵屍對象,僵屍類能夠響應所有的的選擇子,響應方式是:列印一條包含消息内容及其接收者的消息,然後終止應用程式。

有興趣可以參考《編寫高品質iOS與...52個有效的方法》P142。

廢棄retainCount:

對象保留計數看似有用,其實不然,因為任何給定時間點上的"絕對保留計數"都無法反應對象生命期的全貌。

引入ARC之後,retainCount方法就正式廢止了。

本文完。

繼續閱讀