代码之家  ›  专栏  ›  技术社区  ›  Vincent Osinga

cgBitmapContextCreate中存在泄漏

  •  1
  • Vincent Osinga  · 技术社区  · 15 年前

    为了找出代码中的漏洞,我删除了所有不重要的内容,留下了以下代码:

    static int last_memory = 0;
    
    void report_memory(NSString *name) {
        struct task_basic_info info;
        mach_msg_type_number_t size = sizeof(info);
        kern_return_t kerr = task_info(mach_task_self(),
                                       TASK_BASIC_INFO,
                                       (task_info_t)&info,
                                       &size);
        if( kerr == KERN_SUCCESS ) {
            int change = (int)info.resident_size - last_memory;
            NSLog(@"%@ >>> Memory in use: %u (change: %d Kb)", name, info.resident_size, change/1024 );
            last_memory = info.resident_size;
        } else {
            NSLog(@"Error with task_info(): %s", mach_error_string(kerr));
        }
    }
    
    - (CGContextRef) createBitmapContextOfSize:(CGSize) size {
        CGContextRef    context = NULL;
        CGColorSpaceRef colorSpace;
        void *          bitmapData;
        int             bitmapByteCount;
        int             bitmapBytesPerRow;
    
        bitmapBytesPerRow   = (size.width * 4);
        bitmapByteCount     = (bitmapBytesPerRow * size.height);
    
        colorSpace = CGColorSpaceCreateDeviceRGB();
        bitmapData = malloc( bitmapByteCount );
        if (bitmapData == NULL) {
            NSLog(@"Memory not allocated!");
            CGColorSpaceRelease( colorSpace );
            return NULL;
        }
        context = CGBitmapContextCreate (bitmapData,
                                         size.width,
                                         size.height,
                                         8,      // bits per component
                                         bitmapBytesPerRow,
                                         colorSpace,
                                         kCGImageAlphaPremultipliedLast);
        CGContextSetAllowsAntialiasing (context,NO);
        if (context== NULL) {
            free (bitmapData);
            CGColorSpaceRelease( colorSpace );
            NSLog (@"Context not created!");
            return NULL;
        }
        CGColorSpaceRelease( colorSpace );
        return context;
    }
    
    - (IBAction) clickButton:(UIButton *)sender {
        report_memory(@"begin");
        NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"test"];
        UIImage *image = [UIImage imageWithContentsOfFile:path];
    
        report_memory(@"image_created");
    
        CGContextRef myBitmapContext = [self createBitmapContextOfSize:CGSizeMake(256, 256)];
        if (!myBitmapContext){
            return;
        }
        report_memory(@"bitmap_context_created");
        CGContextDrawImage(myBitmapContext, CGRectMake(0, 0, 256, 256), image.CGImage);
        report_memory(@"draw_image");
        CGImageRef ref = CGBitmapContextCreateImage(myBitmapContext);
        report_memory(@"image_context_created");
        CGContextRelease(myBitmapContext);
        report_memory(@"bitmap_context_released");
        UIImage *result = [UIImage imageWithCGImage:ref];
        report_memory(@"image_created");
        CGImageRelease(ref);
        report_memory(@"image_context_released");   
        imageView.image = result;
        report_memory(@"image_assigned");   
    }
    

    (“测试”是256x256 jpeg图像)。 点击几下后,控制台显示如下内容:

    begin >>> Memory in use: 18866176 (change: -12 Kb)
    image_created >>> Memory in use: 18870272 (change: 4 Kb)
    bitmap_context_created >>> Memory in use: 18870272 (change: 0 Kb)
    draw_image >>> Memory in use: 19140608 (change: 264 Kb)
    image_context_created >>> Memory in use: 19140608 (change: 0 Kb)
    bitmap_context_released >>> Memory in use: 19140608 (change: 0 Kb)
    image_created >>> Memory in use: 19140608 (change: 0 Kb)
    image_context_released >>> Memory in use: 19140608 (change: 0 Kb)
    image_assigned >>> Memory in use: 19140608 (change: 0 Kb)
    

    每次点击净损失256KB(等于256x256x4)。在分配性能工具中可以看到相同的趋势。指向cgBitmapContext的所有内容都未被释放。我只是不明白我做错了什么…

    1 回复  |  直到 13 年前
        1
  •  2
  •   Michal    15 年前

    让cgBitmapContextCreate通过提供空值作为第一个参数(BitmapData)来分配内存本身。这将使您从管理内存分配中解脱出来——而目前您还没有释放内存分配。