簡體   English   中英

內存未在使用ARC的iOS應用程序中發布

[英]memory not being released in iOS app using ARC

我用ARC建立了一個簡單的瑣事游戲。 在使用Xcode中的Allocations分析工具分析其內存使用情況時,我發現內存並不總是被釋放。 對於問題的一個示例,我有一個ActivePlayer對象的類:

ActivePlayer.h:

@interface ActivePlayer : NSObject

@property (nonatomic, strong) NSString * name;
@property (nonatomic) NSInteger overallScore;
@property (nonatomic) NSInteger questionScore;

- (id) initWithName:(NSString *)name;

@end

ActivePlayer.m:

#import "ActivePlayer.h"

@interface ActivePlayer ()

@end


@implementation ActivePlayer

- (id) initWithName:(NSString *)name
{
    self = [self init];
    if (self) {
        self.name = name;
        self.overallScore = 0;
    }
    return self;
}

/*
- (void)dealloc
{
    self.name = nil;
}
*/
@end

ActivePlayer是在ActiveGame類的createPlayer方法中創建的:

[[ActivePlayer alloc] initWithName:name]

我正在執行以下測試用例:我開始一個新游戲(分配一個ActivePlayer),我回答一個問題,然后游戲結束(此時ActivePlayer被解除分配)。 然后我可以開始另一個游戲並重復這個循環(每個循環是一個“游戲”,如下所述)。 在使用Allocations性能分析工具時,我期望看到的是內存已經在游戲中分配,但在游戲結束后已經解除分配(無論我玩多少次游戲)。 但我發現情況並非總是這樣:

順便說一句:下面的每個項目符號行描述了“分配”工具的“對象列表”選項卡中的一行; 這個網站不會讓我發布截圖,因此文字描述。 所有行都是Live; 我只查看Created和Still Living分配。

雖然游戲#1正在進行中,但我看到以下分配。

  • 類別= ActivePlayer; 大小= 16; 負責的來電= - [ActiveGame createPlayer:]
  • 類別= Malloc 48字節; 大小= 48; 負責的來電= - [ActivePlayer initWithName:]

比賽#1完成后,我看到以下內容。 ActivePlayer對象已被釋放,但48字節仍然是Live。

  • 類別= Malloc 48字節; 大小= 48; 負責的來電= - [ActivePlayer initWithName:]

如果我開始游戲#2,我會在游戲進行過程中看到以下內容。 除了游戲#1中的一個之外,還有兩個新的分配。

  • 類別= Malloc 48字節; 大小= 48; 負責的來電= - [ActivePlayer initWithName:]
  • 類別= ActivePlayer; 大小= 16; 負責的來電= - [ActiveGame createPlayer:]
  • 類別= Malloc 144字節; 大小= 144; 負責的來電= - [ActivePlayer initWithName:]

在比賽#2完成后,我看到以下內容。 同樣,ActivePlayer對象已被解除分配,但“Malloc X Bytes”分配仍然存在。

  • 類別= Malloc 48字節; 大小= 48; 負責的來電= - [ActivePlayer initWithName:]
  • 類別= Malloc 144字節; 大小= 144; 負責的來電= - [ActivePlayer initWithName:]

在那之后,我得到了不尋常的結果 - 如果我玩游戲#3,#4和#5,我從來沒有看到Category =“Malloc X Bytes”的游戲內行,只有Category = ActivePlayer的新行,這是比賽結束后釋放。 如上所示,前兩個“Malloc”行繼續存在。 我還看到了其他奇怪的行為 - 在昨天使用iPhone 6.0模擬器進行測試時,實時內存僅在游戲#2和#3之后留下,但不是游戲#1,#4和#5。 因此,雖然內存仍然被分配,但它出現的時間似乎因我的設備和不同版本的模擬器而異。

我的問題是:

  • 我的理解是否正確,我不應該在游戲結束后調用initWithPlayer並且ActivePlayer對象已被釋放時看到任何實時內存?
  • 如果是,那是什么導致它,我如何解除分配呢?
  • 或者我根本不需要擔心它?

筆記:

  • 這些截圖來自在運行iOS 6.1的iPhone 4上運行我的應用程序。 但我看到類似的行為與iPhone,iPhone,6.0和6.1的iPhone模擬器一起運行,我在升級之前在運行iOS 6.0的iPhone上看到了它。
  • 在ActivePlayer.m中,dealloc方法目前已被注釋掉了,雖然我已經測試了它,但是它已被取消注釋並且已經驗證它被調用(由系統調用;我不直接在任何地方調用dealloc)。 無論哪種方式,行為都是一樣的。
  • 對於它的價值,泄漏分析工具沒有報告任何內容。
  • 雖然這是一個導致192字節的實時內存的例子,我相信應該被釋放,但是我在很多類中看到了這一點,即看起來內存分配隨着時間的推移而增長,我認為這是一個問題。

您列出的代碼很好。 看起來您仍然在代碼中的其他位置維護對原始ActivePlayer的引用。

作為旁注,您創建ActivePlayer的模式不是常態 - 通常類不會在init方法中調用alloc。 相反,調用者應該執行:

[[ActivePlayer alloc] initWithName:@"Bob"];

並且你的init方法應該使用返回值

[super init];

我覺得很奇怪你的構造函數是靜態的(+符號)。 命名約定要求名稱前綴為init將返回托管內存對象。 我懷疑內部方法的結果是根據其方法名稱進行評估的。

我認為實例計數測試確定您的代碼沒有泄漏ActivePlayers。 順便說一下,構造函數和inits上的更好的形式是這樣的:

// .h

@interface ActivePlayer : NSObject

+ (id)activePlayerWithName:(NSString *)name;

@end

// .m

+ (id)activePlayerWithName:(NSString *)name {
    return [[self alloc] initWithName:name];
}

// if you want to make this public (include in .h interface) you can
// the callers will have the choice of alloc init pattern, or the factory
//
- (id)initWithName:(NSString *)name {
    self = [self init];
    if (self) {
        _name = name;
    }
    return self;
}

然后調用者執行此操作:

ActivePlayer *activePlayer = [ActivePlayer activePlayerWithName:@"Charlie"];

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM