Подтвердить что ты не робот

Разработка iPhone: освобожден указатель

Я получил это сообщение от отладчика:

Pixture(1257,0xa0610500) malloc: *** error for object 0x21a8000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

поэтому я немного исказил и получил:

(gdb) shell malloc_history 1257 0x21a8000

ALLOC 0x2196a00-0x21a89ff [size=73728]: thread_a0610500 |start | main | UIApplicationMain | GSEventRun | GSEventRunModal | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopDoObservers | CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) | CA::Transaction::commit() | CA::Context::commit_transaction(CA::Transaction*) | CALayerDisplayIfNeeded | -[CALayer _display] | CABackingStoreUpdate | backing_callback(CGContext*, void*) | -[CALayer drawInContext:] | -[UIView(CALayerDelegate) drawLayer:inContext:] | -[AvatarView drawRect:] | -[AvatarView overlayPNG:] | +[UIImageUtility createMaskOf:] | UIGraphicsGetImageFromCurrentImageContext | CGBitmapContextCreateImage | create_bitmap_data_provider | malloc | malloc_zone_malloc

и я действительно не могу понять, что я делаю неправильно. здесь код функции [UIImageUtility createMaskOf:]:

+ (UIImage *)createMaskOf:(UIImage *)source {
    CGRect rect = CGRectMake(0, 0, source.size.width, source.size.height);
    UIGraphicsBeginImageContext(CGSizeMake(source.size.width, source.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextTranslateCTM(context, 0, source.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    UIImage *original = [self createGrayCopy:source];

    CGContextRef context2 = CGBitmapContextCreate(NULL, source.size.width, source.size.height, 8, 4 * source.size.width, 
                                                   CGColorSpaceCreateDeviceRGB(), kCGImageAlphaNoneSkipLast);
    CGContextDrawImage(context2, CGRectMake(0, 0, source.size.width, source.size.height), original.CGImage);
    CGImageRef unmasked = CGBitmapContextCreateImage(context2);

    const float myMaskingColorsFrameColor[6] = { 1,256,1,256,1,256 };
    CGImageRef mask = CGImageCreateWithMaskingColors(unmasked, myMaskingColorsFrameColor);

    CGContextSetRGBFillColor (context, 256,256,256, 1);
    CGContextFillRect(context, rect);
    CGContextDrawImage(context, rect, mask);

    UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return whiteMasked;
}

другая пользовательская функция, вызываемая до этого, следующая:

- (UIImage *)overlayPNG:(SinglePart *)sp {
    NSLog([sp description]);
    // Rect and context setup
    CGRect rect = CGRectMake(0, 0, sp.image.size.width, sp.image.size.height);
    NSLog(@"%f x %f", sp.image.size.width, sp.image.size.height);

    // Create an image of a color filled rectangle
    UIImage *baseColor = nil;
    if (sp.hasOwnColor) {
            baseColor = [UIImageUtility imageWithRect:rect ofColor:sp.color];
    } else {
        SinglePart *facePart = [editingAvatar.face.partList objectAtIndex:0];
        baseColor = [UIImageUtility imageWithRect:rect ofColor:facePart.color];
    }

    // Crete the mask of the layer
    UIImage *mask = [UIImageUtility createMaskOf:sp.image];
    mask = [UIImageUtility createGrayCopy:mask];

    // Create a new context for merging the overlay and a mask of the layer
    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
    CGContextRef context2 = UIGraphicsGetCurrentContext(); 

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context2, 0, sp.image.size.height); 
    CGContextScaleCTM(context2, 1.0, -1.0); 

    // Create masked overlay color layer
    CGImageRef MaskedImage = CGImageCreateWithMask (baseColor.CGImage, mask.CGImage);

    // Draw the base color layer
    CGContextDrawImage(context2, rect, MaskedImage);

    // Get the result of the masking
    UIImage* overlayMasked = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    UIGraphicsBeginImageContext(CGSizeMake(sp.image.size.width, sp.image.size.height));
    CGContextRef context = UIGraphicsGetCurrentContext();

    // Adjust the coordinate system so that the origin 
    // is in the lower left corner of the view and the 
    // y axis points up 
    CGContextTranslateCTM(context, 0, sp.image.size.height);
    CGContextScaleCTM(context, 1.0, -1.0);

    // Get the result of the blending of the masked overlay and the base image
    CGContextDrawImage(context, rect, overlayMasked.CGImage);

    // Set the blend mode for the next drawn image
    CGContextSetBlendMode(context, kCGBlendModeOverlay);

    // Component image drawn
    CGContextDrawImage(context, rect, sp.image.CGImage);

    UIImage* blendedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    CGImageRelease(MaskedImage);

    return blendedImage;
}
4b9b3361

Ответ 1

У меня была та же проблема, у меня были такие же симптомы:

  • указатель, освобождаемый, не был назначен ошибкой
  • обновлен до Xcode 3.2
  • ошибка в коде для изображений

Если я изменю цель сборки на 3.1, ошибки в симуляторе исчезнут. Если я запускаю код на устройстве, ошибки не отображаются. Возможно, ошибка в 3.0

Мой совет - протестировать с 3.1 в качестве своей цели, и если вы хотите, вы можете построить для версии 3.0 для выпуска и не беспокоиться об ошибках, поскольку они не происходят на устройстве.

Ответ 2

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

Существует два основных типа ошибок памяти:

  • Выделяет больше, чем вы бесплатно.
  • Освобождение больше, чем вы выделяете.

В этом случае похоже, что вы слишком много освобождаетесь, что легче увидеть (b/c он может сработать раньше), но сложнее отследить.

Вот стратегия, которую вы можете использовать, чтобы помочь найти дополнительные освобождения от ответственности:

  • Отключите некоторые из ваших освобождений.
  • Посмотрите, все еще происходит сбой.

В идеале вы можете найти одну команду удаления, которая при удалении позволит вашему коду работать правильно. Возможно, было бы полезно попробовать подход с бинарным поиском, если это будет практично для вашей кодовой базы. Если это большая база кода, надеюсь, вы используете управление версиями, и вы можете попытаться сосредоточиться на последних различиях.

Имейте в виду, что освобождение от ответственности может быть вызвано несколькими различными способами. Скорее всего, вы вызываете release и autorelease для объектов. Также возможно, что вы можете явно называть dealloc (что обычно является ошибкой). И, конечно, вы можете даже прямо называть free напрямую.

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

Добавлено: Также рекомендуется установить указатель на nil сразу после его выпуска и выполнить его. Таким образом, если вы позже назовете [objectPtr release];, он ничего не сделает.

(PS Btw, мой # 1 самый забавный тип ошибки - это повреждение памяти в mutlithreaded code. У меня был один из них один раз в многомиллионной базе кода.)

Ответ 3

Вероятно, это не причина вашего сбоя, вы теряете память, не отпуская объекты context2, unmasked и mask Core Foundation с использованием CFRelease(), CFImageRelease() и т.п.

Ответ 4

У меня была такая же проблема со следующим кодом.

-(void)adjustImageToImageView:(UIImage*)img{

float numPixels = 100;
float radius = 5;
UIGraphicsBeginImageContext(CGSizeMake(numPixels, numPixels));
CGContextRef c = UIGraphicsGetCurrentContext();

CGContextBeginPath(c);
CGContextMoveToPoint  (c, numPixels, numPixels/2);
CGContextAddArcToPoint(c, numPixels, numPixels, numPixels/2, numPixels,   radius);
CGContextAddArcToPoint(c, 0,         numPixels, 0,           numPixels/2, radius);
CGContextAddArcToPoint(c, 0,         0,         numPixels/2, 0,           radius);
CGContextAddArcToPoint(c, numPixels, 0,         numPixels,   numPixels/2, radius);
CGContextClosePath(c);

CGContextClip(c);

[img drawAtPoint:CGPointZero];
UIImage *converted = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = converted;   }

Я взял эту функцию из приложения с открытым исходным кодом Twitterfon.

Когда я пытался исправить проблему, я попытался изменить последнюю строку на

self.imageView.image = [converted retain]

И это остановило сообщения об ошибках в консоли. Я скоро проверю это в "Утечках", чтобы увидеть, что происходит.

Ответ 5

Я просто хотел еще раз подтвердить, что получал:

освобождаемый указатель не был выделен

и он ушел, если я изменил свою цель os на 3.1, а не 3.0

Ответ 6

Я изо всех сил пытался с той же ошибкой в ​​моем коде. Я был озадачен тем, что мое приложение работало в OS 3.0 без каких-либо проблем, пока я не внес незначительные изменения в код, который не имеет ничего общего с материалом CGImage *. Но как только он начал терпеть неудачу, он никогда не работал без сбоев. Когда я переключился на 3.1, все снова работало. Я сузил ошибку до вызова CGImageRelease(). Либо удаление этой строки, либо добавление сохранения в результирующий UIImage разрешили проблему - хотя это не решение, так как приложение будет утечки памяти.

Я пытался использовать NSZombie с инструментами. Это не помогло - приложение разбилось без обнаружения зомби.

Кроме того, собственные приложения Apple (например, TheElements) НЕ сбой, но использует тот же самый EXACT-код, что и мое приложение. Итак, я изо всех сил пытаюсь принять эту проблему в рамках Рамочной программы. Пока я переключаюсь на 3.1 и двигаюсь дальше.

Ответ 7

Это может быть только я, но вы не можете сделать следующее:

UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

return whiteMasked;

whiteMasked выделяется в стеке функции и после его возврата указатель больше недействителен? Или я чего-то не хватает? Если вы используете возвращенный UIImage *, он не гарантированно останется там. (это был бы хит и промах). Вам не нужно выделять UIImage *, а затем автообновлять его до возвращения?