我想知道对象被自动释放的次数。我已经使用了足够长的目标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框架中找到(或找到可能)。
我同意答案,即使有可能获得自动释放计数更好的工具(僵尸,泄漏,静态分析仪)。
答案 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