2009-09-14 391 views
19

我從調試器這樣的信息: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

我真的不明白wh在我做錯了。這裏的[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; 
} 

回答

27

我有同樣的問題,有很多相同的症狀:被釋放

  • 指針沒有被分配錯誤
  • 升級到3.2的Xcode
  • 錯誤代碼爲發生圖像

如果我將構建目標更改爲3.1,則模擬器中的錯誤將消失。如果我在設備上運行代碼,則不會顯示錯誤。可能是3.0中的一個錯誤

我的建議是以3.1作爲目標進行測試,如果需要,可以爲3.0版本構建版本,而不用擔心錯誤,因爲它們不會在設備上發生。

+0

它看起來像3.0中的一個bug,因爲我也有這個問題,當我將目標設置爲3.1時,它就消失了。 – lucius 2010-01-08 03:23:16

+0

只是說我有完全相同的問題,設置3.1也解決了我的情況。謝謝 – Andy 2010-01-14 21:07:39

+0

另一個「我也是」。看起來像3.0模擬器中的一個錯誤。 3.1+在模擬器和3.0在設備上測試都很好。 – 2010-03-11 04:48:12

22

它看起來像你有一個損壞的內存錯誤,並且很可能是在此碼。損壞的內存錯誤是我的第二個最有趣的錯誤,部分原因是它們通常是非確定性的,並且實際的錯誤命中之後,症狀(又名崩潰)通常發生在之後。

主要有兩種類型的內存錯誤的:

  1. 分配比你更自由。
  2. 超過您的分配空間。

在這種情況下,它看起來像你釋放了太多,這是更容易看到的情況下(B/C它可以先崩潰),但更難追查。

這裏是一個戰略,你可以用它來幫助找到一個額外的釋放操作:

  • 關掉你的一些釋放操作的。
  • 看看是否仍然發生崩潰。

理想情況下,您可以找到一個單獨的釋放命令,當它被移除時,將允許您的代碼正常工作。如果這對您的代碼庫很實用,那麼嘗試二進制搜索方法可能會很有用。如果它是一個很大的代碼庫,希望你使用版本控制,你可以嘗試着重於最近的差異。

請記住,在這裏可以通過幾種不同的方式調用釋放。最有可能的是,您在對象上調用releaseautorelease。也有可能你明確地打電話給dealloc(儘管這通常是個錯誤)。當然,你甚至可以直接明確地撥打free

一旦你擺脫了額外的釋放,最好也檢查內存泄漏(又稱額外分配)。你可以使用儀器和其他工具來做到這一點。開始的一個好地方是在iPhone開發指南中閱讀Finding Memory Leaks

加入:在釋放它並完成使用後,最好設置一個指向nil的指針。這樣,如果您稍後致電[objectPtr release];,它將不會執行任何操作。

(PS順便說一句,我的#1最好玩的錯誤類型是mutlithreaded代碼內存損壞。我有那些曾經在數百萬行的代碼庫之一。)

+0

它你認爲probabl是真實的,也是因爲我發佈的這條消息與應用程序崩潰不對應,它只是在調試控制檯(並減緩應用程序)寫入隨機fashon中,有時會給我2個,有時甚至是4,有時甚至沒有消息...無論如何,我會盡量按照你的指示,看看我能不能到達任何地方。如果我沒有,也許我可以發佈更多的代碼,你可以幫我找到問題? – w4nderlust 2009-09-15 17:52:44

+0

您可以發佈,但在這裏沒有關於詳細的逐行調試的承諾。 Stackoverflow更多的是關於大圖問題或者快速特定問題,而不是費時費力的問題,因爲最後一種問題對其他人來說是最不實用的。此外,爲免費的陌生人做了很多工作;) – Tyler 2009-09-15 18:11:32

+0

我刪除了在第一個消息出來之前加載的所有類中的每個發佈版本調用。我根本沒有結果。我會告訴你前面的函數調用我所展示的函數,希望問題出現在那裏。 (順便說一句,我必須說一個有趣的事情:應用程序沒有這個錯誤,因爲我更新到雪豹和xcode 3.2 ...沒有改變這條線的錯誤出來) – w4nderlust 2009-09-15 19:23:36

3

雖然可能不是原因的崩潰,通過不使用CFRelease(),CFImageRelease()等釋放context2,unmaskedmask核心基礎對象來泄漏內存。

+0

添加了CGContextRelease()和CGImageRelease(),謝謝你的建議;) – w4nderlust 2009-09-15 17:16:22

0

我對以下代碼有同樣的問題。

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

而且,在控制檯停止錯誤消息。我將很快檢查這個漏洞,看看發生了什麼。

+0

我剛跑漏。該應用程序泄露UIImage。所以這絕對不是一個解決方案!有趣的是malloc錯誤被這個壓制了。 – infiniteloop 2009-09-24 15:17:06

0

我只是想確認,再次,我已經是越來越:被釋放

指針沒有被分配

錯誤,如果我改變我的目標操作系統它走了3.1而不是3.0

+0

是的,我也一樣。 'UIGraphicsGetImageFromCurrentImageContext()'應該返回一個自動發佈的UIImage,但它似乎是雙重autoreleasing它,只在3.0模擬器中,並且只使用Xcode 3.2 – 2010-03-19 17:44:53

0

我在我的代碼中遇到了同樣的錯誤。我感到困惑的是,我的應用程序在OS 3.0中工作沒有任何問題,直到我對與CGImage *東西無關的代碼進行了小小的修改。但是一旦它開始失敗,那麼它不會崩潰。當我切換到3.1時,一切都恢復正常。我將錯誤縮小爲CGImageRelease()調用。無論是移除該行還是在生成的UIImage上添加保留都解決了問題 - 儘管這是一個無法解決的問題,因爲該應用會泄漏內存。

我試過用儀器使用NSZombie。這沒有幫助 - 應用程序崩潰沒有任何殭屍被發現。此外,蘋果自己的示例應用程序(如TheElements)不會崩潰,但會使用與我的應用程序相同的EXACT代碼。所以,我很難接受框架中存在的問題。目前,我正在轉向3.1並繼續前進。

0

這可能只是我,但你不能做到以下幾點?

UIImage *whiteMasked = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext(); 

return whiteMasked; 

whiteMasked是分配在該函數的堆棧上,並且在它返回指針後不再有效?或者我錯過了什麼?如果您使用返回的UIImage *,則不能保證仍然存在。 (這將是一個命中和錯過)。你不需要分配一個UIImage *,然後在返回之前自動釋放它?

+0

Cocoa/Objective-C中的對象始終分配在堆上,從不在堆棧上。存儲在'whiteMasked'中的指針至少在當前自動釋放池被排空之前是有效的,直到事件循環結束爲止。在這個函數中使用它很好,也可以返回它。如果我們打算保存它並稍後使用相同的圖像(例如,在一個實例變量中),我們只需要製作一個副本。 – benzado 2010-06-04 05:55:53

相關問題