7

我上具有使用Web服务和核心数据在一个紧密的循环同步过程中的iPad应用工作。根据Apple's Recomendation我分配减少内存占用和周期性漏极的NSAutoreleasePool。这目前效果很好,目前的应用程序没有内存问题。但是,我打算转移到ARC,因为NSAutoreleasePool不再有效,并希望保持这种相同的性能。我创建了几个例子和定时他们我想知道什么是最好的方法,使用ARC,以acheive同类性能和维护代码的可读性降低峰值内存使用@autoreleasepool

出于测试目的,我想出了3个场景,每个创建使用1和10,000,000之间的数字的字符串。我跑了每个示例3次,以确定他们是否使用与苹果LLVM编译器3.0在Mac 64位应用程序所用的时间(W/O GDB -O0)和XCode的4.2。我还通过仪器运行每个示例来大致了解记忆峰值。

以下每个都包含在下面的代码块中的例子:

int main (int argc, const char * argv[]) 
{ 
    @autoreleasepool { 
     NSDate *now = [NSDate date]; 

     //Code Example ... 

     NSTimeInterval interval = [now timeIntervalSinceNow]; 
     printf("Duration: %f\n", interval); 
    } 
} 

NSAutoreleasePool批次[原件预ARC](峰值记忆:〜116 KB)

static const NSUInteger BATCH_SIZE = 1500; 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
    { 
     NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
     [text class]; 

     if((count + 1) % BATCH_SIZE == 0) 
     { 
      [pool drain]; 
      pool = [[NSAutoreleasePool alloc] init]; 
     } 
    } 
    [pool drain]; 

运行时间:
10.928158
10.912849
11.084716


外@autoreleasepool(峰值存储器:〜382 MB)

@autoreleasepool { 
     for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 

运行时间:
11.489350
11.310462
11.344662


内@autoreleasepool(峰值记忆:〜61.2KB)

for(uint32_t count = 0; count < MAX_ALLOCATIONS; count++) 
    { 
     @autoreleasepool { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 

运行时间:
14.031112
14.284014
14。099625


@autoreleasepool瓦特/ GOTO(峰值存储器:〜115KB)

static const NSUInteger BATCH_SIZE = 1500; 
    uint32_t count = 0; 

    next_batch: 
    @autoreleasepool { 
     for(;count < MAX_ALLOCATIONS; count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
      if((count + 1) % BATCH_SIZE == 0) 
      { 
       count++; //Increment count manually 
       goto next_batch; 
      } 
     } 
    } 

运行时间:
10.908756
10.960189
11.018382

goto声明提供最接近的性能,但它采用的是goto。有什么想法吗?

更新:

注:goto声明是在documentation表示不会泄漏内存的@autoreleasepool一个正常的退出。

在进入时,会推送自动释放池。在正常退出(中断, 返回,转到,通过,等等)自动释放池被弹出。 为了与现有代码兼容,如果退出是由于例外造成的,则 自动释放池不会弹出。

+1

使用优化。这对ARC代码来说非常重要。 – 2012-03-12 21:58:20

+0

因此'goto'肯定不是,我不知道,导致内存泄漏?其他一切都合情合理:减少排水速度更快。无论如何,我只能评论可读性:在任何你游泳池都很好。那个goto需要一个黄色的粘滞便笺。 – 2012-03-12 21:58:42

+0

goto似乎没有泄漏任何内存。看起来像我期望的那样排除了autorelease池的范围,但我不是ARC的专家(还),并且不想依赖UB。 – Joe 2012-03-12 22:07:06

回答

9

下应达到同样的事情goto答案没有goto

for (NSUInteger count = 0; count < MAX_ALLOCATIONS;) 
{ 
    @autoreleasepool 
    { 
     for (NSUInteger j = 0; j < BATCH_SIZE && count < MAX_ALLOCATIONS; j++, count++) 
     { 
      NSString *text = [NSString stringWithFormat:@"%u", count + 1U]; 
      [text class]; 
     } 
    } 
} 
+0

谢谢,漫长的一天,简单的答案:)。 – Joe 2012-03-13 00:07:51

+1

这应该是更多投票,因为它正是解决方案,以获得与旧的'NSAutoreleasePool'手动排水一样的行为! – mattjgalloway 2012-03-26 16:55:10

2

注意,ARC使得未在-O0启用显著优化。如果要在ARC下测量性能,那么必须在启用优化的情况下测试。否则,您将根据ARC的“朴素模式”测量您手动调整的保留/释放位置。

通过优化再次运行您的测试并查看会发生什么。

更新:我很好奇,所以我自己跑了。这些是发布模式(-Os)的运行时结果,具有7,000,000个分配。

arc-perf[43645:f803] outer: 8.1259 
arc-perf[43645:f803] outer: 8.2089 
arc-perf[43645:f803] outer: 9.1104 

arc-perf[43645:f803] inner: 8.4817 
arc-perf[43645:f803] inner: 8.3687 
arc-perf[43645:f803] inner: 8.5470 

arc-perf[43645:f803] withGoto: 7.6133 
arc-perf[43645:f803] withGoto: 7.7465 
arc-perf[43645:f803] withGoto: 7.7007 

arc-perf[43645:f803] non-ARC: 7.3443 
arc-perf[43645:f803] non-ARC: 7.3188 
arc-perf[43645:f803] non-ARC: 7.3098 

和Memory峰(仅10万个拨款运行,因为仪器正在采取永远):

Outer: 2.55 MB 
Inner: 723 KB 
withGoto: ~747 KB 
Non-ARC: ~748 KB 

这些结果让我感到惊讶了一点。那么,记忆峰值结果不会;这正是你所期望的。但是即使启用了优化,innerwithGoto之间的运行时间差也比我预期的要高。

当然,这是一种病态的微观测试,很难模拟任何应用程序的真实世界的性能。这里要说的是ARC可能确实存在一些开销,但在做出假设之前,您应该始终测量您的实际应用。

(另外,我使用嵌套的for循环测试@ ipmcc的答案,它的表现几乎完全一样的goto版本)。

+0

谢谢,感谢小费。没有意识到采取了额外的步骤,但从那时起就是绝对的。是否有类似于http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html的优化指南?不期望找到确切的标志,但更多地沿着什么样的优化可能发生的路线。我发现了一些有用的属性项[这里](http://clang.llvm.org/docs/AutomaticReferenceCounting.html#optimization),但它看起来并不像编译器优化所依赖的。 – Joe 2012-03-13 18:01:57

+0

我添加了一些真实世界的测试,启用优化。 – 2012-03-13 21:02:50

+0

感谢您的帮助,通过优化检查统计信息。这对于决定将来使用哪种方法用于各种目的很有用(除了'goto'感谢ipmcc的回答以外)。希望有更多的人能够通过并积极参与。 – Joe 2012-03-13 21:23:10