如何判断对象是否在NSAutoreleasePool中

时间:2011-09-22 14:53:49

标签: objective-c ios memory-leaks nsautoreleasepool retaincount

我想知道对象被自动释放的次数。我已经使用了足够长的目标c,通常可以直接知道某个对象是否已经自动释放,但是我经常会看到处理内存和保留计数的问题。在某些时候,答案总是结束,“你不能相信对象的retainCount” - 我同意,但如果你能确定一个对象被自动释放的次数,那么你实际上可以信任 retainCount,如果您添加了类别:

@interface NSObject (NSObject_MemoryDebugging)
- (NSUInteger) autoReleaseCount;
- (NSUInteger) retainCountWithAutoRelease;
@end

@implementation]
/** Determine how many times this object has been marked for autorelease **/
- (NSUInteger) autoReleaseCount;
{
   // ??? not sure how to figure this out.
   return 0;
}

 - (NSUInteger) retainCountWithAutoRelease
{
   NSUInteger retainCount = [self retainCount];
   NSUInteger autoReleaseCount = [self getAutoReleaseCount];  // ???
   return retainCount - autoReleaseCount;
}
@end

对于不可变类型仍然存在异常,因为这些通常会在复制期间增加保留计数,因此您仍然无法信任retainCount。

我不建议

我不是在生产代码中使用retainCount来寻求此答案。但是,我可以看到这对于调试内存问题的人来说很有价值。

我想有些人会讨厌这个问题,因为程序员不应该关心对象被自动释放的次数。编码应该是关于平衡分配,保留,复制,新版本和故事结束。然而,重点是帮助人们敲打头脑。 [NSObject retainCount]烧掉了很多人,对这个问题的回答会非常酷。

我确定有一种方法可以确定一个对象被自动释放的次数。我只是不知道它是什么,因此问题。

请参阅类似问题:Objects inside NSAutoreleasePool in objective-c

修改


谢谢大家的回答。你可能会发现这个有趣的=> Ariel指出GNUStep的Cocoa实现,特别是它的NSAutoReleasePool有这种方法:+(NSUInteger)autoreleaseCountForObject:(id)anObject。此方法很慢,只返回调用者线程上NSAutoReleasePools的自动释放计数。还是......有趣的是它在那里。文档引用它实际上只对调试有用。这真的是我希望以某种方式在Cocoa框架中找到(或找到可能)。

我同意答案,即使有可能获得自动释放计数更好的工具(僵尸,泄漏,静态分析仪)。

4 个答案:

答案 0 :(得分:7)

首先,您必须处理多个自动释放池和一个多次自动释放的对象,可能在多个池中。

其次,它不是(仅仅)NSAutoreleasePool使得-retainCount不值得信任。问题在于各种各样的物品,无论是你的还是苹果的,都会出于各种原因而保留物品,这是你们最不为人知的。即使考虑自动释放,你的对象通常也没有你期望的保留计数,因为在幕后,某些东西正在观察它或暂时将它放在字典中等等。

调试内存问题的最佳方法是Leaks仪器,NSZombie和静态分析仪。

答案 1 :(得分:5)

不,没有公共API来确定对象是否已被自动释放。

即使这是公开的,您的-retainCountWithAutoRelease方法也会遇到一些问题:

  • 对象可以在同一个自动释放池中多次放置,因此您需要一个自动释放池的自动释放计数,而不是指示对象是否已自动释放的标志;

  • 由于多线程,对象可以放在多个自动释放池中,因此您需要一个跨越多个自动释放池的自动释放计数;

  • 由于多线程,您需要将代码与Cocoa处理保留计数和自动释放池同步,并且Cocoa使用的内部锁定对应用程序不可见。

答案 2 :(得分:1)

NSAutoreleasePool确实有一个我以前完全没有意识到的+(void)showPools方法。这可能很有用。另请参阅Is there a way to inspect an NSAutoreleasePool's objects?。在那个帖子中,KennyTM说(在评论中):

  

好吧,因为内容被打印到stderr,你可以重新打开   流并从中解析以获取所有指针

作为参考,我使用针对Foundation框架的class-dump来查看它的NSAutoreleasePool细节,它有以下内容:

@interface NSAutoreleasePool : NSObject {
    void *_token;
    void *_reserved3;
    void *_reserved2;
    void *_reserved;
}

+ (void)addObject:(id)arg1;
+ (id)allocWithZone:(struct _NSZone *)arg1;
+ (void)showPools;
+ (void)releaseAllPools;
+ (unsigned int)autoreleasedObjectCount;
+ (unsigned int)topAutoreleasePoolCount;
+ (BOOL)autoreleasePoolExists;
+ (void)enableRelease:(BOOL)arg1;
+ (void)enableFreedObjectCheck:(BOOL)arg1;
+ (unsigned int)poolCountHighWaterMark;
+ (void)setPoolCountHighWaterMark:(unsigned int)arg1;
+ (unsigned int)poolCountHighWaterResolution;
+ (void)setPoolCountHighWaterResolution:(unsigned int)arg1;
+ (unsigned int)totalAutoreleasedObjects;
+ (void)resetTotalAutoreleasedObjects;
- (id)init;
- (void)drain;
- (oneway void)release;
- (id)initWithCapacity:(unsigned int)arg1;
- (void)addObject:(id)arg1;
- (id)retain;
- (unsigned int)retainCount;
- (id)autorelease;
- (void)dealloc;
@end

我添加了这个作为答案,因为它似乎更像是一个答案,而不是我问的问题的更多细节。

答案 3 :(得分:0)

听起来你需要覆盖-(id)autorelease;方法作为在NSAutoreleasePool添加对象的工作。
类似的东西:

-(id)autorelease{
    _isAutoreleased = YES;  //some BOOL member initialized to NO and returned on -(BOOL)isAutoreleased;
    [NSAutoreleasePool  addObject:self];
    return self;
}

另请查看this link