8

我想知道一个对象被自动释放了多少次。我使用objective 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 的答案。但是,我认为这对于调试内存问题的人很有价值。

我想有些人会讨厌这个问题,因为程序员不应该关心一个对象被自动释放了多少次。编码应该是关于平衡分配、保留、复制、新的发布、故事的结尾。但是,这样做的目的是帮助人们敲打他们的头。 [NSObject retainCount]烧了很多人,这个问题的答案会很酷。

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

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

编辑


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

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

4

4 回答 4

7

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

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

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

于 2011-09-22T15:13:52.443 回答
5

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

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

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

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

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

于 2011-09-22T15:14:31.153 回答
1

NSAutoreleasePool 确实有一个+(void)showPools我以前完全不知道的方法。这可能很有用。另请参阅是否有办法检查 NSAutoreleasePool 的对象?. 在那个线程上,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

我已将此添加为答案,因为它似乎更像是一个答案,而不是我提出的问题的更多细节。

于 2011-09-23T15:15:06.430 回答
0

听起来您需要重写-(id)autorelease;方法作为添加对象的NSAutoreleasePool工作。
像这样的东西:

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

也看看这个链接

于 2011-09-22T15:21:28.263 回答