【问题标题】:why does none retained pointer need to use release?为什么没有保留指针需要使用释放?
【发布时间】:2012-08-16 01:55:13
【问题描述】:

我有两个问题,但让我们先从更容易混淆的问题开始。

-(void)OnNewFrameData:(NSData *)FrameData 
{
    UIImage * I = [UIImage imageWithData:FrameData];
    [I release];
}

如果我不释放I,我会遇到内存泄漏。然而,我从未保留I。有人可以解释一下吗? (FrameData 完全由调用者管理。)

然后我还有一个关于保留属性的问题。取上面相同的代码,将I分配给保留属性J,然后将nil分配给相同的保留属性,应该没有任何泄漏,但我又泄漏了内存。我也可以释放保留的属性,但我仍然会泄漏。

@property (retain) UIImage * J;

...

-(void)OnNewFrameData:(NSData *)FrameData 
{
    UIImage * I = [UIImage imageWithData:FrameData];
    self.J = I;
    // I can also add here [self.J release]; and it still leaks...
    self.J = nil;
    [I release];
}

非常感谢从我从文档和 stackoverflow 的线程中学到的知识中了解这两个令人困惑的明显矛盾。

【问题讨论】:

  • 你如何确定你的内存是否泄漏?
  • 两三分钟后(不超过)我收到两个内存警告,1 和 2,然后程序被 iOS 退出。视频帧的大小很大,所以我认为它们正在消耗内存并且没有被释放。我可以运行相同的代码大约半小时,并且没有收到任何警告,表明我没有泄漏内存。有更好的方法吗?
  • 使用 Xcode 提供的工具工具:raywenderlich.com/2696/…
  • 仪器工具崩溃了,根本没有说明为什么我会收到内存警告。或者至少它的神秘信息没有给我太多任何线索。

标签: objective-c ios


【解决方案1】:

[UIImage imageWithData] 是一种方便的方法,可以执行以下操作。

-(UIImage*)imageWithData:(NSData*)data{
   UIImage *img = [[UIImage alloc] initWithData:data];
   [img autorelease];

   return img;
}

如您所见,有一个 alloc 将保留计数设置为 1。希望这可以澄清。如果我可以进一步澄清,请发表评论。我刚刚被提示将图像放置在自动释放池中,如果您想在池耗尽后保留它,则应该在创建时保留它。

那么正确的方法就是使用。

 [[UIImage imageWithdata:data]retain];

在执行此操作时,保留计数为 2,在池耗尽时将减少 1。因此,您应该仍然只需要一个版本。

p.s 您可能还想运行分析器。它将指出任何内存问题。 (CMD + shift + b)

另一个想法。你能检查一下 i 不是零吗?文档说如果创建 UIImage 不成功,它将返回 nil,这可能是一个问题。

【讨论】:

  • 我不认为这是正确的,因为imageWithData: 不是allocnewcopy 等命名方法,它应该返回一个自动释放的对象
【解决方案2】:

于是我用下面的代码做了个实验……

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    UIImage * Img = [[UIImage imageWithData:FrameData] retain];
    [pool drain];

    int n = [Img retainCount];

在上面的代码中,Img 的保留计数返回 1。如果我删除自动释放池,则为 2。这是绝对清楚的证据,表明 imageWithData: 返回了一个自动释放的对象,这正是我们所期望的。

所以我唯一的结论是池没有足够快地释放 Img,并且它们正在池中通过网络传输的每个连续图像。最后我的内存用完了。

如果没有人对原始问题的第一部分有任何其他想法,我将不得不以此作为答案。

关于第二个问题,我仍然没有任何线索。

更新:

一直让我困惑的是,主线程上标记为自动释放的对象如何及时释放?我一直认为自动释放就像一个垃圾收集器,只要内存池内存不足,它就会运行。但回顾文献,很明显 GB 不是自动释放池的意义所在,因为它在非 GB 环境中可用。自动释放池不会释放任何对象,直到池被耗尽消息销毁。

那么主线程对象呢?为什么他们不累积直到程序结束?因为(我在这里推测,但这是最合乎逻辑的解释)每次框架调用我们的一个类对象(更新:我说的是框架在调度事件时调用我们的代码),它首先设置一个新的自动释放池。因此,框架对我们的类对象之一的任何方法调用中的所有对象都被一个新池包围,并且当框架从我们的代码接收控制权时,所有标记为自动释放的对象都将被释放。

如果有人有任何信息可以进一步阐明这一点,我非常希望收到您的来信。

【讨论】:

  • 没有。不不不不不。不要碰-retainCount。假装该方法不存在。我不在乎你在做什么,只是不要。
  • 我非常清楚访问retainCount 的问题。我访问这里只是为了测试 [pool drain] 的行为,我们都假设是来自 imageWithData 的自动释放对象引用。
  • 有趣的是,有人否决了我的答案,但无法用更好的解释来解释我所看到的......
  • 你的推测是错误的。主线程默认只有1个自动释放池,由NSRunLoop创建。每次它分派一个事件时,它都会创建一个新池。而且这里绝对没有类似 GC 的行为。自动释放的对象会在其周围的自动释放池被释放时被销毁。
  • 这不是我说的吗?好吧,我没有说“调度事件”,但我确实说“每次框架调用我们的类对象之一”。我怀疑您的描述仅在措辞上更准确..
猜你喜欢
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-26
  • 2010-12-11
相关资源
最近更新 更多