导致设备内存泄漏的位图
Bitmap causing memory leak on device
我正在使用简单的位图技术将文本转换为图像,然后将此图像划分为光栅,然后计算每个光栅矩形中黑色像素的百分比。在模拟器上一切正常,但在 Device.here 上崩溃是一些相关代码
-(int)blackValue:(UIImage *)image rect:(CGRect)rect {
int pixelInRect = (int)rect.size.width * rect.size.height;
__block int blackCount = 0;
ImageBitmap * imageBitmap = [[ImageBitmap alloc] initWithImage:image bitmapInfo:(CGBitmapInfo)kCGImageAlphaNoneSkipLast];
for (int x = 0; x <(int) rect.size.width; x++) {
for (int y = 0; y < (int) rect.size.height; y++) {
Byte * pixel = [imageBitmap pixelAtX:(int)rect.origin.x Y:(int)rect.origin.y];
Byte red = pixel[0];
if (red < 0.1)
{
blackCount++;
}
}
}
return blackCount/pixelInRect;
}
- (NSDictionary *)rasterizeBitmap:(UIImage *)image size:(CGFloat)size {
CGFloat width =(int) (image.size.width/size);
CGFloat height =(int) (image.size.height/size);
NSMutableArray *fields = [NSMutableArray array];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
CGRect rect = CGRectMake(x * size, y * size, size, size);
CGPoint center = CGPointMake(x * size + size/2.0, image.size.height - (y * size + size/2.0));
double black = [self blackValue:image rect:rect];
Field * field = [[Field alloc] init];
field.center = center;
field.black = black;
[fields addObject:field];
}
}
return @{@"width":@(width) , @"fields":fields};
}
当我尝试 运行 它在配置文件中时,我得到了以下结果
有人可以建议我如何解决内存问题吗?
问题是您在 ImageBitmap
对象中手动分配内存,但您永远不会释放它。
两个可疑点是位图上下文 (context
) 和位图数据 (contextData
)。这两个都不是由 ARC 管理的,因此您需要在完成后自行释放它们。
在 ARC 中,您可以简单地在 ImageBitmap
class 中实现 dealloc
方法并将清理代码放在那里。
例如:
-(void) dealloc {
CGContextRelease(context); // releases the bitmap context, if it was created (CGContextRelease checks for NULL)
free(contextData); // releases the bitmap data (it was explicitly created, so no need to check)
}
同样值得注意的是,您应该使 init
不可用,并标记您指定的初始化程序。
这是因为您 不能 使用您的 imageFromContext
和 pixelAtX:Y:
实例方法,而无需通过自定义 initWithSize:bitmapInfo:
初始化器创建您的实例,因为它创建位图上下文并为位图数据分配内存。
因此,如果您通过调用 init
创建您的实例并调用您的实例方法之一,您很可能会崩溃。
要解决此问题,您可以在 ImageBitmap.h
文件中将 init
方法标记为不可用,并将 initWithSize:bitmapInfo:
方法标记为指定的初始化程序。
-(instancetype) init NS_UNAVAILABLE;
-(id)initWithSize:(CGSize)size bitmapInfo:(CGBitmapInfo)bmInfo NS_DESIGNATED_INITIALIZER;
NS_UNAVAILABLE
所做的只是阻止您通过调用 init
创建您的实例,迫使您使用自定义初始化程序。
如果您尝试执行 [[ImageBitmap alloc] init]
,编译器将显示以下错误:
NS_DESIGNATED_INITIALIZER
所做的只是确保 ImageBitmap
中的任何额外初始化器必须通过您的初始化器创建新实例,如果不这样做,将向您显示以下警告:
See here for more info on NS_DESIGNATED_INITIALIZER
.
现在,实际上这些实际上只是形式,因为您是唯一要使用它的人,并且您知道您必须使用自定义初始化程序。但是,如果您想与其他人共享您的代码,最好办理好这些手续。
我正在使用简单的位图技术将文本转换为图像,然后将此图像划分为光栅,然后计算每个光栅矩形中黑色像素的百分比。在模拟器上一切正常,但在 Device.here 上崩溃是一些相关代码
-(int)blackValue:(UIImage *)image rect:(CGRect)rect {
int pixelInRect = (int)rect.size.width * rect.size.height;
__block int blackCount = 0;
ImageBitmap * imageBitmap = [[ImageBitmap alloc] initWithImage:image bitmapInfo:(CGBitmapInfo)kCGImageAlphaNoneSkipLast];
for (int x = 0; x <(int) rect.size.width; x++) {
for (int y = 0; y < (int) rect.size.height; y++) {
Byte * pixel = [imageBitmap pixelAtX:(int)rect.origin.x Y:(int)rect.origin.y];
Byte red = pixel[0];
if (red < 0.1)
{
blackCount++;
}
}
}
return blackCount/pixelInRect;
}
- (NSDictionary *)rasterizeBitmap:(UIImage *)image size:(CGFloat)size {
CGFloat width =(int) (image.size.width/size);
CGFloat height =(int) (image.size.height/size);
NSMutableArray *fields = [NSMutableArray array];
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
CGRect rect = CGRectMake(x * size, y * size, size, size);
CGPoint center = CGPointMake(x * size + size/2.0, image.size.height - (y * size + size/2.0));
double black = [self blackValue:image rect:rect];
Field * field = [[Field alloc] init];
field.center = center;
field.black = black;
[fields addObject:field];
}
}
return @{@"width":@(width) , @"fields":fields};
}
当我尝试 运行 它在配置文件中时,我得到了以下结果
有人可以建议我如何解决内存问题吗?
问题是您在 ImageBitmap
对象中手动分配内存,但您永远不会释放它。
两个可疑点是位图上下文 (context
) 和位图数据 (contextData
)。这两个都不是由 ARC 管理的,因此您需要在完成后自行释放它们。
在 ARC 中,您可以简单地在 ImageBitmap
class 中实现 dealloc
方法并将清理代码放在那里。
例如:
-(void) dealloc {
CGContextRelease(context); // releases the bitmap context, if it was created (CGContextRelease checks for NULL)
free(contextData); // releases the bitmap data (it was explicitly created, so no need to check)
}
同样值得注意的是,您应该使 init
不可用,并标记您指定的初始化程序。
这是因为您 不能 使用您的 imageFromContext
和 pixelAtX:Y:
实例方法,而无需通过自定义 initWithSize:bitmapInfo:
初始化器创建您的实例,因为它创建位图上下文并为位图数据分配内存。
因此,如果您通过调用 init
创建您的实例并调用您的实例方法之一,您很可能会崩溃。
要解决此问题,您可以在 ImageBitmap.h
文件中将 init
方法标记为不可用,并将 initWithSize:bitmapInfo:
方法标记为指定的初始化程序。
-(instancetype) init NS_UNAVAILABLE;
-(id)initWithSize:(CGSize)size bitmapInfo:(CGBitmapInfo)bmInfo NS_DESIGNATED_INITIALIZER;
NS_UNAVAILABLE
所做的只是阻止您通过调用 init
创建您的实例,迫使您使用自定义初始化程序。
如果您尝试执行 [[ImageBitmap alloc] init]
,编译器将显示以下错误:
NS_DESIGNATED_INITIALIZER
所做的只是确保 ImageBitmap
中的任何额外初始化器必须通过您的初始化器创建新实例,如果不这样做,将向您显示以下警告:
See here for more info on NS_DESIGNATED_INITIALIZER
.
现在,实际上这些实际上只是形式,因为您是唯一要使用它的人,并且您知道您必须使用自定义初始化程序。但是,如果您想与其他人共享您的代码,最好办理好这些手续。