Разработка 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(@"%fx %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; } 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

     -(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] 

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

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

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

    ошибка, и она ушла, если я изменил свою целевую ОС на 3.1, а не на 3.0

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

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

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

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

     UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return whiteMasked; 

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

    Давайте будем гением компьютера.