【问题标题】:Bitmap causing memory leak on device位图导致设备内存泄漏
【发布时间】:2016-06-18 07:10:51
【问题描述】:

我正在使用简单的位图技术将文本转换为图像,然后我将此图像划分为光栅,然后我正在计算每个光栅矩形中黑色像素的百分比。在模拟器上一切正常,但在设备上崩溃。这是一些相关代码

-(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};
}

当我尝试在 Profile 中运行它时,我得到了以下结果

有人可以建议我如何解决内存问题吗?

【问题讨论】:

    标签: ios objective-c memory-leaks bitmap core-graphics


    【解决方案1】:

    问题是您在 ImageBitmap 对象中手动分配内存,但您从未释放它。

    这两个嫌疑犯是位图上下文 (context) 和位图数据 (contextData)。这两个都不是由 ARC 管理的,所以一旦你完成了它们,你会想要自己释放它们。

    在 ARC 中,您可以简单地在 ImageBitmap 类中实现 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 不可用,并标记您指定的初始化程序。

    这是因为您不能使用您的 imageFromContextpixelAtX: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.

    现在,实际上这些只是形式,因为您是唯一将使用它的人,并且您知道您必须使用自定义初始化程序。但是,如果您想与其他人共享您的代码,最好做好这些手续。

    【讨论】:

    • 很好的观察.. 我只是在设备中运行它。你让我开心。:)
    • @Shazad 乐于提供帮助 :)
    • 一切正常,我将接受您的回答。但在此之前,我想问一下您答案的第二部分,即在自定义初始化程序中分配内存(init 不可用)。您能解释一下吗?
    猜你喜欢
    • 2016-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-10
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    相关资源
    最近更新 更多