关于C#:NSAutoreleasePool自动释放池如何工作?

关于C#:NSAutoreleasePool自动释放池如何工作?

How does the NSAutoreleasePool autorelease pool work?

据我了解,使用alloc,new或copy创建的任何内容都需要手动释放。 例如:

1
2
3
4
5
6
int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

我的问题是,这样难道不是同样有效吗?:

1
2
3
4
5
6
7
8
int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}

是的,您的第二个代码段是完全有效的。

每次将-autorelease发送给对象时,都会将其添加到最内部的autorelease池中。当池耗尽时,它仅向池中的所有对象发送-release。

自动释放池只是一种便利,它使您可以将发送-释放推迟到"以后"。"后期"可能会在多个地方发生,但是在Cocoa GUI应用程序中最常见的是当前运行循环周期的结尾。


NSAutoreleasePool:消耗与释放

由于drainrelease的功能似乎引起混乱,因此在这里可能需要澄清(尽管在文档中已对此进行了介绍)。

严格来说,从大角度看,drain不等同于release

在引用计数的环境中,drain确实执行与release相同的操作,因此两者在此意义上是等效的。要强调的是,这意味着如果使用drain而不是release,则不会泄漏池。

在垃圾回收的环境中,release是空操作。因此,它没有任何作用。另一方面,drain包含向收集器的提示,提示它应"根据需要收集"。因此,在垃圾回收的环境中,使用drain有助于系统平衡回收扫描。


如前所述,您的第二个代码段是正确的。

我想提出一种使用自动释放池的更简洁的方法,该池适用于所有环境(引用计数,GC,ARC),并且还可以避免浪费/释放混乱:

1
2
3
4
5
6
7
int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

在上面的示例中,请注意@autoreleasepool块。在此处记录。


不你错了。该文档明确指出,在非GC环境下,-drain等效于-release,这意味着NSAutoreleasePool将不会泄漏。


向对象发送自动释放而不是释放,至少可以延长该对象的寿命,直到耗尽池本身为止(如果随后保留该对象,则可能会更长)。一个对象可以多次放入同一个池中,在这种情况下,每次将对象放入池中时都会收到释放消息。


我从苹果那里读到的东西:
"在自动释放池块的末尾,向在该块内接收到自动释放消息的对象发送释放消息-每次在该块内向其发送自动释放消息时,对象都会收到释放消息。"

https://developer.apple.com/library/mac/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html


是的,没有。您最终将释放字符串内存,但是如果在垃圾回收(非内存托管)环境下运行NSAutoreleasePool对象,则使用排水而不是释放将NSAutoreleasePool对象"泄漏"到内存中。此"泄漏"仅使NSAutoreleasePool的实例像其他任何在GC下没有强指针的对象一样"不可访问",并且该对象将在下次GC运行时被清除,这很可能直接在调用-drain之后进行:

drain

In a garbage collected environment, triggers garbage collection if memory allocated since last collection is greater than the current threshold; otherwise behaves as release.
...
In a garbage-collected environment, this method ultimately calls objc_collect_if_needed.

否则,它类似于-release在非GC下的行为,是的。如其他人所述,-release在GC下是无操作的,因此确保池在GC下正常运行的唯一方法是通过-drain,而在非GC下,-drain的工作方式与在下的-release完全相同。非GC,并且可以说也更清楚地传达了其功能。

我应该指出,您的语句"用new,alloc或init调用的任何内容"都不应包含" init"(但应包含" copy"),因为" init"不分配内存,它只会设置对象(构造函数)时尚)。如果收到分配对象并且函数仅这样调用init,则不会释放该对象:

1
2
3
4
- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

这不会消耗比您开始时更多的内存(假设init不会实例化对象,但是无论如何您都不会对这些对象负责)。


推荐阅读

    linux命令创建用户组?

    linux命令创建用户组?,系统,代码,密码,用户组,用户,命令,信息,名称,新增,管

    linux创建主机名命令?

    linux创建主机名命令?,工作,地址,系统,信息,名称,命令,目录,发行,查询系统,

    linux控制台创建命令?

    linux控制台创建命令?,工作,地址,系统,命令,信息,目录,管理,名字,文件,控制

    创建自定义命令linux?

    创建自定义命令linux?,工具,状态,命令,系统,代码,标准,数据,位置,电脑,材料,L

    linux命令如何创建与?

    linux命令如何创建与?,名字,文件,命令,名称,系统,密码,首次,文件名,终端,文

    linux下创建网络命令?

    linux下创建网络命令?,网络,地址,工作,系统,管理,命令,名字,最新,项目,设备,l

    linux命令创建项目组?

    linux命令创建项目组?,管理,密码,项目,命令,系统,位置,文件,用户组,用户,文

    linux的创建目录命令?

    linux的创建目录命令?,名字,地址,位置,密码,软件,系统,命令,目录,文件夹,文

    linux创建端口命令?

    linux创建端口命令?,系统,网络,服务,通讯,检测,工具,端口,电脑,命令,以下,Lin

    linux创建内容的命令?

    linux创建内容的命令?,名字,文件,命令,密码,时间,系统,文件名,终端,目录,文

    linux释放权限的命令?

    linux释放权限的命令?,系统,档案,代码,地址,密码,命令,管理,工具,工作,简介,L

    linux下文件创建命令?

    linux下文件创建命令?,名字,名称,首次,命令,文件,系统,密码,文件名,文件夹,

    linux创建vp命令?

    linux创建vp命令?,系统,工作,基础,设备,地址,命令,目录,环境,信息,工具,linux

    linux系统工作命令?

    linux系统工作命令?,系统,工作,地址,设备,信息,标准,命令,单位,发行,数据,Lin

    linux命令创建文件加?

    linux命令创建文件加?,名字,管理,系统,名称,密码,首次,命令,文件,文件夹,位

    linux按命令创建磁盘?

    linux按命令创建磁盘?,系统,信息,业务,号码,数据,情况,电脑,分区,较大,工具,

    linux命令中创建文本?

    linux命令中创建文本?,系统,时间,文件,终端,名字,名称,发行,命令,文件夹,文

    linux常用命令创建?

    linux常用命令创建?,地址,系统,工作,时间,命令,管理,文件,目录,路径,控制台,l

    文件创建linux命令?

    文件创建linux命令?,名字,时间,名称,系统,首次,文件,命令,密码,文件名,目录,L

    linux创建软链接命令?

    linux创建软链接命令?,工作,地址,位置,系统,信息,管理,服务,名字,链接,文件,