好吧,我有一个难以追踪内存泄漏的世界。运行此脚本时,我没有看到任何内存泄漏,但我的objectalloc正在攀爬。 Instruments指向CGBitmapContextCreateImage> create_bitmap_data_provider> malloc,这占我的objectalloc的60%。
使用NSTimer多次调用此代码。
//GET IMAGE FROM RESOURCE DIR
NSString * fileLocation = [[NSBundle mainBundle] pathForResource:imgMain ofType:@"jpg"];
NSData * imageData = [NSData dataWithContentsOfFile:fileLocation];
UIImage * blurMe = [UIImage imageWithData:imageData];
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
UIImage * scaledImage = [blurMe _imageScaledToSize:CGSizeMake(blurMe.size.width / dblBlurLevel, blurMe.size.width / dblBlurLevel) interpolationQuality:3.0];
UIImage * labelImage = [scaledImage _imageScaledToSize:blurMe.size interpolationQuality:3.0];
UIImage * imageCopy = [[UIImage alloc] initWithCGImage:labelImage.CGImage];
[pool drain]; // deallocates scaledImage and labelImage
imgView.image = imageCopy;
[imageCopy release];
以下是模糊功能。我相信objectalloc问题位于此处。也许我只需要一双新鲜的眼睛。如果有人能想到这一点会很棒。对不起,它有点长......我会试着缩短它。
@implementation UIImage(Blur)
- (UIImage *)blurredCopy:(int)pixelRadius
{
//VARS
unsigned char *srcData, *destData, *finalData;
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
//IMAGE SIZE
size_t pixelsWide = CGImageGetWidth(self.CGImage);
size_t pixelsHigh = CGImageGetHeight(self.CGImage);
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateDeviceRGB();
if (colorSpace == NULL) { return NULL; }
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL) { CGColorSpaceRelease( colorSpace ); }
context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedFirst );
if (context == NULL) { free (bitmapData); }
CGColorSpaceRelease( colorSpace );
free (bitmapData);
if (context == NULL) { return NULL; }
//PREPARE BLUR
size_t width = CGBitmapContextGetWidth(context);
size_t height = CGBitmapContextGetHeight(context);
size_t bpr = CGBitmapContextGetBytesPerRow(context);
size_t bpp = (CGBitmapContextGetBitsPerPixel(context) / 8);
CGRect rect = {{0,0},{width,height}};
CGContextDrawImage(context, rect, self.CGImage);
// Now we can get a pointer to the image data associated with the bitmap
// context.
srcData = (unsigned char *)CGBitmapContextGetData (context);
if (srcData != NULL)
{
size_t dataSize = bpr * height;
finalData = malloc(dataSize);
destData = malloc(dataSize);
memcpy(finalData, srcData, dataSize);
memcpy(destData, srcData, dataSize);
int sums[5];
int i, x, y, k;
int gauss_sum=0;
int radius = pixelRadius * 2 + 1;
int *gauss_fact = malloc(radius * sizeof(int));
for (i = 0; i < pixelRadius; i++)
{
.....blah blah blah...
THIS IS JUST LONG CODE THE CREATES INT FIGURES
........blah blah blah......
}
if (gauss_fact) { free(gauss_fact); }
}
size_t bitmapByteCount2 = bpr * height;
//CREATE DATA PROVIDER
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, srcData, bitmapByteCount2, NULL);
//CREATE IMAGE
CGImageRef cgImage = CGImageCreate(
width,
height,
CGBitmapContextGetBitsPerComponent(context),
CGBitmapContextGetBitsPerPixel(context),
CGBitmapContextGetBytesPerRow(context),
CGBitmapContextGetColorSpace(context),
CGBitmapContextGetBitmapInfo(context),
dataProvider,
NULL,
true,
kCGRenderingIntentDefault
);
//RELEASE INFORMATION
CGDataProviderRelease(dataProvider);
CGContextRelease(context);
if (destData) { free(destData); }
if (finalData) { free(finalData); }
if (srcData) { free(srcData); }
UIImage *retUIImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return retUIImage;
}
我能想到的唯一一件事就是举起objectalloc就是这个UIImage * retUIImage = [UIImage imageWithCGImage:cgImage]; ...但是如何在它返回后释放它?希望有人可以帮忙。
答案 0 :(得分:4)
我多次使用过Quartz。每次我做的都是一场噩梦。据我注意到,我已经填写了一个关于苹果发送项目作为崩溃证据的错误,其中一件事情是真的:
我曾经创建了一个简单的项目来证明这一点。该项目有一个按钮。每次按下按钮时,屏幕上都会添加一个小图像(100x100像素)。图像由两层组成,图像本身和包含围绕图像边界绘制的虚线的附加层。这张图是在Quartz中完成的。按下按钮8次使应用程序崩溃。你可以说:按下按钮8次,屏幕上增加了16个图像,这就是崩溃的原因,对吗?
我没有使用Quartz绘制边框,而是决定在PNG上预先绘制边框,然后将其作为图层添加到对象中。每个对象创建相同的两个图层。正确?
我点击了100次,在屏幕上添加了200张图片,没有崩溃。记忆永远不会超过800 Kb。我可以继续点击......应用程序继续快速而快速。没有内存警告,没有崩溃。
Apple必须紧急审查Quartz。
答案 1 :(得分:1)
获取clang并通过它运行您的项目。它不仅会发现你的(静态)泄漏,它还会帮助你更多地了解引用计数规则 - 至少它对我有用。
答案 2 :(得分:0)
我见过类似的行为,并阅读了其他几篇类似的帖子。创建自动释放池似乎没有帮助。看起来这个库正在泄漏内存或将其存储在更高级别的自动释放池中,因此它不会被发布,直到为时已晚。我怀疑框架中有一个错误但无法证明它。
答案 3 :(得分:0)
如果您实际将图像分配和释放包装在池对象存在周期中,它会有所帮助,
pool = [[NSAutoreleasePool alloc] init];
[imageView setImage: [UIImage imageNamed:"image1.png"]];
...
[imageView setImage: [UIImage imageNamed:"image2.png"]];
...
[imageView setImage: [UIImage imageNamed:"image3.png"]];
....
[pool drain];
[pool release];
在此示例中,不会释放image3.png,但是image1和image2将是。
答案 4 :(得分:0)
一些想法/想法:
首先,这段代码显然存在问题,因为如果上下文无法分配,你可以释放两次bitmapData。
if (context == NULL) { free (bitmapData); }
CGColorSpaceRelease( colorSpace );
free (bitmapData);
if (context == NULL) { return NULL; }
我同意你的bitata数据,直到你完成上下文...虽然它不是崩溃,这是令人费解的。幸运也许。
请注意,我非常确定数据提供程序和位引用将成为CGImageCreate返回的cgImage的一部分:
提供商 位图的数据源。有关支持的数据格式的信息,请参阅下面的讨论。 Quartz保留了这个对象;回来后,你可以安全地释放它。
所以,这意味着在你返回的UIImage被释放之前,我认为cgImage或位数据提供者不会消失。那么,也许问题是UIImage并不是每个人都会消失?
为什么不使用CGBitmapContextCreateImage()来创建生成的图像? (您可能需要调用CGContextFlush()来强制绘制到位图,但看起来您正在手动更改所有像素,因此可能不需要)。
基于模糊的文档,我认为你不应该自由地()使用CGBitmapContextGetData返回的指针(但由于文档的模糊性,这有点猜测)。
也:
你没有初始化srcData,destData&amp; finalData为NULL,所以你在free()之前的测试看起来很冒险。
所有这些(并且尝试了一些这些东西),我们的Mac App一度漏洞,因为在10.5.6和更早的某些方面CIImage imageWithCGImage,imageByApplyingTransofrm,imageByCroppingToRect,NSBitmapImageRep initWithCIImage或NSBitmapImageRep CGImage泄露。这已在10.5.7中修复,因此您正在测试的iPhone OS版本中可能存在类似的内容。
答案 5 :(得分:0)
实际上,如果我记得[UIImage imageNamed]创建了自己的缓存,这是你无法控制的。这将考虑您所看到的内存使用情况。您可以在此处阅读更多内容 - http://www.alexcurylo.com/blog/2009/01/13/imagenamed-is-evil/。
答案 6 :(得分:0)
使用CGBitmapContextCreate(..)时,我遇到了同样的问题,随机发生泄漏并构建。
我通过使用不同的函数从位图数据创建UIImage来解决这个问题:
尝试:
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
或
provider = CGDataProviderCreateWithData( (void *)pixelBuffer, sourceBaseAddr, sourceRowBytes * height, ReleaseCVPixelBufferFunction);
CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width
cvMat.rows, // Height
8, // Bits per component
8 * cvMat.elemSize(), // Bits per pixel
cvMat.step, // Bytes per row
colorSpace, // Colorspace
kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags
provider, // CGDataProviderRef
NULL, // Decode
false, // Should interpolate
kCGRenderingIntentDefault); // Intent
答案 7 :(得分:0)
如果您正在使用垃圾回收,请使用CFMakeCollectable(posterFrame)。如果您正在使用传统的内存管理,那么它非常简单:
return (CGImageRef)[(id)posterFrame autorelease];
您将CFTypeRef(在本例中为CGImageRef)转换为Objective-C对象指针,向其发送-autorelease消息,然后将结果转换回CGImageRef。此模式适用于(几乎)任何与CFRetain()和CFRelease()兼容的类型。