w4n*_*ust 19 iphone memory-leaks memory-management objective-c
我从调试器得到这条消息:
Pixture(1257,0xa0610500) malloc: *** error for object 0x21a8000: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Run Code Online (Sandbox Code Playgroud)
所以我做了一些跟踪并得到了:
(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;
}
Run Code Online (Sandbox Code Playgroud)
之前调用的另一个自定义函数如下:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
nev*_*ing 27
我有同样的问题,有很多相同的症状:
如果我将构建目标更改为3.1,模拟器中的错误就会消失.如果我在设备上运行代码,则不会出现错误.可能是3.0中的错误
我的建议是以3.1为目标进行测试,如果需要,可以为3.0版本进行构建,而不用担心错误,因为它们不会在设备上发生.
Tyl*_*ler 22
看起来你有一个损坏的内存错误,它可能不在这个代码中.损坏的内存错误是我第二个最有趣的错误,部分原因是它们通常是非确定性的,并且症状(即崩溃)通常在实际错误发生后很久就会发生.
有两种主要类型的内存错误:
在这种情况下,它看起来像你正在释放太多,这是更容易看到的情况(b/c它可以提前崩溃),但更难追查.
您可以使用以下策略来帮助查找额外的解除分配:
理想情况下,您可以找到一个单独的释放命令,删除后,将允许您的代码正常工作.如果这对您的代码库很实用,那么尝试使用二进制搜索方法可能会很有用.如果它是一个很大的代码库,希望你使用版本控制,你可以尝试专注于最近的差异.
请记住,这里可以通过几种不同的方式调用解除分配.最有可能的,你打电话release和autorelease对象上.您也可能明确地调用dealloc(但这通常是一个错误).当然,你甚至可以free直接明确地打电话.
一旦你摆脱了额外的解除分配,最好还要检查内存泄漏(也就是额外的分配).您可以使用Instruments和其他工具完成此操作.一个好的起点是阅读iPhone开发指南中的Finding Memory Leaks.
补充:nil在你发布指针并使用指针完成后立即设置指针也是一个好主意.这样,如果你[objectPtr release];稍后打电话,它将不会做任何事情.
(PS顺便说一下,我最有趣的错误类型是多线程代码中的内存损坏.我有一个曾经在数百万行代码库中.)