首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用ARC在NSMutableArray中释放对象?

如何使用ARC在NSMutableArray中释放对象?
EN

Stack Overflow用户
提问于 2014-04-25 17:34:52
回答 2查看 2.1K关注 0票数 6

我原来的工程漏水了,所以我去找漏水的地方。当我发现它时,我创建了一个简单的新项目。该项目使用ARC,我添加的唯一代码如下。

代码语言:javascript
复制
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    int elements = 10000000;
    //memory usage 5,2 MB

    NSMutableArray *array = [NSMutableArray arrayWithCapacity:elements];
    //memory usage 81,7 MB

    for (int i = 0; i < elements; i++) {
        [array addObject:[NSObject new]];
    }
    //memory usage 234,3 MB

    [array removeAllObjects];
    //memory usage 234,3 MB

    array = nil;
    //memory usage 159,5 MB
}

调用数组removeAllObjects后,数组中的所有NSObjects都应该被取消分配,内存使用量应该再次达到81,7MB。我做错了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-04-25 18:29:41

你被可怕的自动释放池咬了。本质上,为了使MRC (手动引用计数)由人们管理,而不是立即释放一个对象,它可以立即将其传递给自动释放池( NSAutoreleasePool的一个实例,它的文档给出了更多的细节),这将保留该对象,直到稍后池被耗尽为止。电弧(自动参考计数)可以设计,这样的自动释放机械是不需要的,但保持与MRC的兼容性。

在运行循环周期结束时,池会自动排出--即当应用程序完成处理事件时。但是,如果应用程序创建了大量临时对象,然后丢弃它们,则使用本地自动释放池可以大大减少内存的最大使用。这并不是说这样的临时对象不会被释放,只是因为它们的寿命将远远超过所需时间。可以使用@autoreleasepool { ... }构造创建本地池。

通过包装整个applicationDidFinishLaunching:,您可以在示例中看到效果

代码语言:javascript
复制
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
   @autoreleasepool
   {
      ...
   }
}

并逐步完成调试器。

在真正的代码中,您需要从产生大量临时对象的点开始工作,以找到一个适当的点来添加一个自动释放池。

HTH。

增编

当您认为应该释放的时候,并不是数组中的对象没有被释放,您可以使用一个简单的类来测试它,它可以计数初始化和释放,例如:

@interface TestObject : NSObject

代码语言:javascript
复制
+ (void) showCounts;

@end

@implementation TestObject

static uint64_t initCount = 0, deallocCount = 0;

- (id) init
{
    self = [super init];
    if(self) initCount++;
    return self;
}

- (void) dealloc
{
    deallocCount++;
}

+ (void) showCounts
{
    NSLog(@"init: %llu | dealloc: %llu", initCount, deallocCount);
    initCount = deallocCount = 0;
}
@end

使用这个代替NSObject,并在测试完成后调用showCounts --尝试使用/不使用自动发布,等等。

你的记忆总是被释放,问题就在于它释放的时间。有些对象在自动释放池中结束,或者是默认的,每个事件清空一次,或者是本地的。

除非您创建了许多临时对象来响应单个事件,否则通常不会看到问题。考虑一下,您是否在为您的应用程序寻找一个真正的问题。如果你是试图缓解问题的其中之一,那就是:

  • 避免使用表单<name>WithX...的方便构造函数,后者是[[[C alloc] initWithX...] autorelease]的缩写。在许多情况下,但不是所有情况下,编译器都可以在方便构造函数返回后从自动释放池中删除此类对象(您的情况似乎是这样的)。更好的方法是使用alloc/initnew (alloc/init的缩写)或(如果提供) newWithX... (alloc/initWithX...的缩写)。在示例中尝试这些选项,并查看内存何时释放(而不是是否释放)的差异。
  • 放置良好的@autoreleasepool块。

HTH

票数 1
EN

Stack Overflow用户

发布于 2014-04-25 17:54:23

这里

代码语言:javascript
复制
NSMutableArray *array = [NSMutableArray arrayWithCapacity:elements];

您正在创建自动释放对象(自动释放池)。

许多程序创建自动释放的临时对象。这些对象会增加程序的内存占用,直到块结束。在许多情况下,允许临时对象累积到当前事件循环迭代的结束并不会导致过多的开销;然而,在某些情况下,您可能会创建大量的临时对象,这些对象大大增加了内存占用,并且希望更快地处理这些对象。在后一种情况下,您可以创建自己的自动释放池块。在块的末尾,临时对象被释放,这通常会导致它们的释放,从而减少程序的内存占用

@autoreleasepool {}方法[NSMutableArray arrayWithCapacity:elements]包装

代码语言:javascript
复制
NSMutableArray *array;
@autoreleasepool {
    array = [NSMutableArray arrayWithCapacity:elements];
    // [NSMutableArray arrayWithCapacity:] creates object with retainCount == 1
    // and pushes it to autorelease pool

    // array = some_object; usually (and in this case also) is transformed by ARC to 
    // [array release]; [some_object retain]; array = some_object;

    // so here array will have retainCount == 2 and 1 reference in autorelease pool

} // here autorelease pool will call `release` for its objects.
// here array will have retainCount == 1

或者更改为

代码语言:javascript
复制
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:elements];
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23299562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档