自动释放的对象何时真正释放?

Posted

技术标签:

【中文标题】自动释放的对象何时真正释放?【英文标题】:When is an autoreleased object actually released? 【发布时间】:2011-01-30 16:44:51 【问题描述】:

我是 Objective-c 的新手,我正在尝试了解内存管理以使其正确。

在阅读了苹果的优秀Memory Management Programming Guide for Cocoa 之后,我唯一关心的是什么时候 实际上,自动释放的对象是在 iphone/ipod 应用程序中释放的。我的理解是在运行循环的末尾。但是什么定义了应用程序中的运行循环?

所以我想知道下面的代码是否正确。假设一个对象

@implementation Test

- (NSString *) functionA 
    NSString *stringA;
    stringA = [[[NSString alloc] initWithString:@"Hello"] autorelease]
    return stringA;


- (NSString *) functionB 
    NSString *stringB;
    stringB = [self functionA];
    return stringB;


- (NSString *) functionC 
    NSString *stringC;
    stringC = [self functionB];
    return stringC;


- (void)viewDidLoad 
    [super viewDidLoad];
    NSString* p = [self functionC];
    NSLog(@"string is %@",p);


@end

此代码有效吗?

从苹果的文字中,我了解到从 functionA 返回的 NSString 在 functionB 的范围内是有效的。我不确定它在 functionC​​trong> 和 viewDidLoad 中是否有效。

谢谢!

【问题讨论】:

【参考方案1】:

该代码没有任何问题。它将按照您的预期编译和运行。

functionA 返回的NSString 对象在返回时仍然有效,因为它正在堆栈中向下传递给正在跟踪它的下一个人 (functionB)。

【讨论】:

“向下传递堆栈”可能不是短语的最佳选择,因为它暗示堆栈用于返回值,但并非总是如此。【参考方案2】:

是的,您的函数是有效的,并且使用正确的 Cocoa 约定来返回对象,用于保留/释放/自动释放/复制。

要回答关于什么是 runloop 的问题,在应用程序的 main() 函数中,它会调用 UIApplicationMain()。你可以想象 UIApplicationMain 看起来像这样:

void int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName) 
    UIApplication *app = /* create app using principalClassName */;
    [app setDelegate:/* create delegate using delegateClassName */];
    while (![app shouldTerminate]) 
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        event = [app getNextEvent];
        [app dispatchEvent:event];
        [pool drain];
    

while 循环类似于 UIKit 实际在执行的操作,并且每次通过该 while 循环就像一次通过 runloop,函数 getNextEvent 阻塞等待某个事件发生。您的所有方法通常都是从 dispatchEvent: 之类的内部调用的。您可以尝试在您的一个方法中设置断点,例如 IBAction,然后在顶部的调试器调用堆栈中查看处理事件和运行循环的 UIKit 方法的名称。由于您的每个方法都是从该 while 循环中调用的,因此每次对对象调用 autorelease 时,该对象都会添加到运行循环中的该外部池中。当当前事件完成分发时,池被清空,这些对象最终被发送释放消息。

最后一点。可以有不止一个自动释放池,它们并不总是在事件循环的末尾。有时,您可能会在整个事件循环中一次分配数万个对象。发生这种情况时,您可能会在自己的方法中设置额外的内部自动释放池,以减少自动释放池中自动释放对象的数量。自动释放池可以堆叠。

【讨论】:

我是否理解正确,如果我没有创建任何自动释放池,所有自动释放的变量都将保留在内存中,直到应用程序没有关闭? 类似,系统框架会在主线程堆栈的顶部以 UIApplicationMain() 等方法为您创建一些自动释放池。但是,如果您启动了自己的线程,并且没有创建池,那么是的,这些对象会泄漏。在这种情况下,自动释放方法会记录到控制台。 好的,谢谢,但是这很奇怪,通常的做法是使用返回自动释放对象而不释放它们的构造函数,但实际上与发生内存泄漏相同(分配了内存)直到申请结束)。还是我有什么不明白的地方? 由 UIApplicationMain 等函数为您创建的自动释放池每次通过事件循环时都会被耗尽一次。所以物体会很频繁地消失。如果您创建自己的线程,然后在该线程上创建自动释放对象,则需要定期排空并重置自动释放池。 好的,谢谢 Jon,现在说得通了,唯一的问题是我不太清楚这种情况下的事件循环是什么,你能举个事件的例子吗?

以上是关于自动释放的对象何时真正释放?的主要内容,如果未能解决你的问题,请参考以下文章

自动释放对象递减的保留计数何时减少?

何时使用自动释放变量? [复制]

分配和释放 VS。自动释放。为啥和何时?

读书笔记iOS-自动释放池

linux何时自动释放内存

在 Objective-C 中如何处理 Autorelease 池中的对象?