循环内的 Objective-C 循环和 @autoreleasepool 的 ARC 内存问题

Posted

技术标签:

【中文标题】循环内的 Objective-C 循环和 @autoreleasepool 的 ARC 内存问题【英文标题】:Objective-C loop within loop and ARC memory issues with @autoreleasepool 【发布时间】:2015-01-20 09:45:45 【问题描述】:

我有一种情况,我必须在另一个 for 循环中使用 for 循环。

当迭代次数不是很大(

但有时迭代次数可能非常大。内部循环总是有一些有限的数量(在我的例子中是 20),但外部循环从非常小到非常大(可以达到 100000)不等。

类似这样的事情会导致内存不足错误,应用会被终止:

    @autoreleasepool 
    NSMutableArray *array = [NSMutableArray array];
    for(int i=0; i<1000000;i++)
        @autoreleasepool 
            NSString *dataString = dataArray[i];
            NSArray *temp = [dataString componentsSeparatedByString:@","];

            NSString *string1 = @"";
            NSString *string2 = @"";
            NSString *string3 = @"";

            for(int j=0; j<20; j++)
                NSString *tag = temp[j];
                NSArray *kv = [tag componentsSeparatedByString:@":"];
                switch ([kv[0] intValue]) 
                    case 0:
                        string1 = kv[1];
                        break;
                    case 1:
                        string2 = kv[1];
                        break;
                    case 2:
                        string3 = kv[1];
                        break;

                    default:
                        break;
                
            

            NSString *final = [NSString stringWithFormat:@"%@ %@ %@", string1, string2, string3];
            [array addObject:final];

        
    
    [self process:array];
    // process array

@autoreleasepool 似乎根本没有工作(几乎相同数量的内存使用和不使用 @autoreleasepool 块)

我尝试删除内部循环(仅用于测试)并且代码正常工作并且每次迭代后都会释放内存。但是当使用内部循环时,内存不会被释放,最终应用程序会因内存不足而终止。

如果我在这里做错了什么,谁能告诉我,我找不到解决方案。

已编辑

哦,愚蠢的我:)

我发现了这个问题,它与循环或任何事情无关。 其中一个开关盒有一个日期字符串,我需要将该字符串转换为另一种日期格式

    NSDateFormatter *dFormatter = [[NSDateFormatter alloc] init];
    [dFormatter setDateFormat:fromFormat];
    NSDate *date = [dFormatter dateFromString:dateString];
    [dFormatter setDateFormat:toFormat];
    NSString *newDateString = [dFormatter stringFromDate:date];
    return newDateString;

所以这段代码的每个外部循环都会运行一次,这是让我的内存不断填充直到崩溃的代码。

所以我每次都停止创建新的 NSDateFormatter 并制作两个格式化程序作为全局格式化程序。所以现在我的代码运行顺利:)

    [self.formatter setDateFormat:fFormat];
    NSDate *date = [self.formatter dateFromString:dateString];
    [self.dOnlyFormatter setDateFormat:tFormat];
    NSString *newDateString = [self.dOnlyFormatter stringFromDate:date];
    return newDateString;

但我不明白为什么这些 NSDateFormatter 对象在方法完成后没有得到 dealloc。

【问题讨论】:

代码示例是产生问题的实际代码还是简化版本? 它是一个简化版本 - 但实际代码有类似的循环 - 第一个循环处理一个字符串数组,第二个循环将循环通过对第一个数组中的字符串进行标记获得的数组,最终字符串将是添加到全局数组 - 但这个全局数组似乎不会引起任何问题 - 我会将真实代码附加到问题中 非简化版是否在外面的数组中添加了任何东西? 你应该发布真正的循环,我猜作为 Fonix,确实发生了一些从“内到外”创建引用的事情,因此自动释放池不会有效 是的,您更新的代码显示您添加到自动释放池之外的数组中,因此您只是存储了太多对象以适应内存,因此您需要以某种方式优化内存占用 【参考方案1】:

试试这个:

NSMutableArray *array = [NSMutableArray array];
NSString *final;
NSString *string1;
NSString *string2;
NSString *string3;
NSString *const empty = @"";
NSString *const x = @"x";
NSString *const y = @"y";
NSString *const z = @"z";

for(int i=0; i<100000;i++)

        string1 = empty;
        string2 = empty;
        string3 = empty;

        for(int j=0; j<20; j++) // if we remove this loop this works perfectly
            switch (j) 
                case 0:
                    string1 = x;
                    break;
                case 1:
                    string2 = y;
                    break;
                case 2:
                    string3 = z;
                    break;

                default:
                    break;
            
        

        final = [NSString stringWithFormat:@"%@ %@ %@", string1, string2, string3];


作为一个积极的副作用,它可能会更快。

【讨论】:

实际上当我删除 NSString *string1 = @"";从循环并在循环之前添加它,它开始使用的内存比以前少得多,但仍然没有解决原始问题,但现在它在错误之前处理了更多的迭代,如果有任何解决方案,我将对此进行处理 您可以尝试再次添加自动释放池,因为您仍然经常为新字符串分配新内存。这就是所有以“string”或“copy”开头的 NSString 方法实际上所做的。 (您甚至可以在原始代码的第二个循环中使用@autoreleasepool。这将使用我的代码解决内存分配问题,实际上避免了不必要的分配) 顺便说一句,它运行得更快吗? 有什么意义? final 将阻塞外部自动释放池,并且在您的情况下不使用数组。我可以建议删除此代码,因为它不会做任何副作用,因为您会获得更快的速度。

以上是关于循环内的 Objective-C 循环和 @autoreleasepool 的 ARC 内存问题的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C学习笔记——循环语句for和do-while的使用

使用Objective-C中的单例保留循环

用于 for 循环内动画的 Objective-C 完成块(暂停循环处理)

在 Objective-C 中循环 BOOL

Block循环引用问题(Objective-c)

如何打破 Objective-C 中的两个嵌套 for 循环?