После 15000 итераций появляется сообщение об ошибке: «невозможно выделить регион» - нет предупреждения о памяти - PullRequest
1 голос
/ 26 января 2012

Баллов: с помощью ARC; полная ошибка:

malloc: * mmap (размер = 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];
}

Есть идеи, в чем может быть проблема? Заранее спасибо!

РЕДАКТИРОВАТЬ: преобразование между CString и NSString является болью с ARC. Так что я пошел с @autoreleasepool{} внутри циклов (и nil вместо NULL), и это значительно сократило использование памяти. У меня более 50 тысяч итераций.

Ответы [ 2 ]

1 голос
/ 26 января 2012

Так что у самой программы есть некоторые проблемы, если она использует столько памяти - вы можете значительно сократить использование памяти этим алгоритмом.

В любом случае, вы не получите предупреждение памяти , если это происходит в главном потоке. Предупреждение о памяти делается в главном потоке, и вы не даете ему возможности обработать предупреждение, поскольку вы исчерпываете память до того, как цикл выполнения основного потока получит еще один шанс выполнить свою обычную работу (например, обработать предупреждения памяти или обработать другие события).

Возможно, вы бы увидели что-то другое, если бы это произошло во вторичном потоке, но это не решило бы корень проблемы.

0 голосов
/ 26 января 2012

Вы рекурсивно решаете проблему, которая заполняет память.

Ваш компьютер должен отслеживать, куда идти после завершения каждого из 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;
}
...