经过15000次迭代后,得到“错误:无法分配区域” - 没有内存警告

时间:2012-01-26 02:15:35

标签: objective-c nsmutablearray xcode4.2 automatic-ref-counting

要点:使用ARC; 完整错误是:

  

malloc: * mmap(size = 2097152)失败(错误代码= 12)    错误:无法分配区域   * *在malloc_error_break中设置断点以进行调试

四次。

问题的唯一代码是:

-(void)iterate:(NSString *)string{
    frontString = NULL;
    backString = NULL;
    arrayOfNumbers = NULL;
    backwardArrayOfNumbers = NULL;
    nextString = NULL;
    nextArrayOfNumbers = NULL;
    nextArrayOfNumbers = [NSMutableArray new];
    nextString = [NSMutableString new];
    backwardArrayOfNumbers = [NSMutableArray new];
    arrayOfNumbers = [NSMutableArray new];
    frontString = [[NSMutableString alloc] initWithString:string];
    backString = [NSMutableString new];
    if (string.length > 1) {
        iteration++;
        for (unsigned long i = 0; i < string.length; ++i) {
            NSString *sub = [string substringWithRange:(NSRange){i, 1}];
            [arrayOfNumbers addObject:sub];
            NSString *back = [string substringWithRange:(NSRange){string.length-(i+1), 1}];
            [backwardArrayOfNumbers addObject:back];
            [backString appendString:back];
            sub = NULL;
            back = NULL;
        }

        if ([frontString isEqualToString:backString]) {
            [palindromicNumberTextView setText:string];
            [iterationLabel setText:[NSString stringWithFormat:@"%ld", iteration]];
        } else {
            int carrier = 0;
            for (long long j = arrayOfNumbers.count-1; j > -1; --j) {
                int a = [[arrayOfNumbers objectAtIndex:j] intValue];
                int b = [[backwardArrayOfNumbers objectAtIndex:j] intValue];
                //NSLog(@"a = %i, b = %i", a, b);

                int c = a+b+carrier;
                if (c > 9) {
                    c = c-10;
                    carrier = 1;
                } else {
                    carrier = 0;
                }

                [nextArrayOfNumbers addObject:[NSString stringWithFormat:@"%i", c]];
                if (carrier == 1 && (nextArrayOfNumbers.count == arrayOfNumbers.count)) {
                    [nextArrayOfNumbers addObject:[NSString stringWithFormat:@"%i", carrier]];
                }
                //NSLog(@"nextArrayOfNumbers = %@", nextArrayOfNumbers);
            }

            for (int i = 0; i < nextArrayOfNumbers.count; ++i) {
                NSString *back = [nextArrayOfNumbers objectAtIndex: nextArrayOfNumbers.count-(i+1)];
                //NSLog(@"back = %@", back);
                [nextString appendString:back];
                back = NULL;

            }
            if (iteration%1000 == 0) {
                NSLog(@"iteration %ld; count:%u", iteration, nextArrayOfNumbers.count);
            }
            //NSLog(@"iteration %ld", iteration);
            [self iterate:nextString];
        }
    }
}

以后15,000次迭代,崩溃+错误,没有内存警告:

- (void)didReceiveMemoryWarning
{
    NSLog(@"Error near iteration %ld", iteration);
    [super didReceiveMemoryWarning];
}

任何想法可能是什么问题?提前谢谢!

编辑:在CStringNSString之间转换对ARC来说很痛苦。所以我在循环中使用了@autoreleasepool{}(而nil而不是NULL),这大大减少了内存使用量。我的迭代次数超过了50k。

2 个答案:

答案 0 :(得分:1)

因此程序本身在使用那么多内存时会遇到一些问题 - 你可以大大减少这个算法的内存使用量。

无论如何,如果发生在主线程上,你将不会收到内存警告。内存警告是在主线程上发出的,你没有机会处理警告,因为在主线程的运行循环有另一次机会完成其正常工作(例如处理内存警告或处理其他事件)之前耗尽内存。

如果这种情况发生在辅助线程上,也许你会看到不同的东西,但这并不能解决问题的根源。

答案 1 :(得分:0)

你正在递归地解决一个填满内存的问题。

当计算机完成15,000个周期中的每一个周期时,您必须记录下去的地方。这可能会成为很多空间。

如果可以使这个“尾递归”,你可以节省空间。例如:

"bad" recursion which saves in memory 7 + 6 + 5 + 4 + 3 + 2
int factorial (int x)
{
  if (x > 1)
  {
     return (x + recursion (x - 1));
  }
  else return x;
}

//

good recursion start with y = 1
only saves in memory two integers, updating them every cycle.
int factorial (int x, int y)
{
  if (x > 1)
  {
     return factorial (x - 1, (x * y));
  }
  else return x;
}