0

I am trying to get the rgb color from an image at the position where the image was tapped. However after multiple taps the app crashes due to low memory.

This is the class where the leak is happening:

import Foundation
class PixelExtractor {

    let image: CGImage
    let context: CGContextRef

    var width: Int {
        get {
            return CGImageGetWidth(image)
        }
    }

    var height: Int {
        get {
            return CGImageGetHeight(image)
        }
    }

    init(img: CGImage) {
        image = img
        context = PixelExtractor.create_bitmap_context(img)
    }

    private class func create_bitmap_context(img: CGImage)->CGContextRef {

        // Get image width, height
        let pixelsWide = CGImageGetWidth(img)
        let pixelsHigh = CGImageGetHeight(img)

        // Declare the number of bytes per row. Each pixel in the bitmap in this
        // example is represented by 4 bytes; 8 bits each of red, green, blue, and
        // alpha.
        let bitmapBytesPerRow = pixelsWide * 4
        let bitmapByteCount = bitmapBytesPerRow * Int(pixelsHigh)

        // Use the generic RGB color space.
        let colorSpace = CGColorSpaceCreateDeviceRGB()

        // Allocate memory for image data. This is the destination in memory
        // where any drawing to the bitmap context will be rendered.
        let bitmapData = malloc(bitmapByteCount)
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)

        // Create the bitmap context. We want pre-multiplied ARGB, 8-bits
        // per component. Regardless of what the source image format is
        // (CMYK, Grayscale, and so on) it will be converted over to the format
        // specified here by CGBitmapContextCreate.
        let context = CGBitmapContextCreate(bitmapData, pixelsWide, pixelsHigh, 8, bitmapBytesPerRow, colorSpace, bitmapInfo.rawValue)

        // draw the image onto the context
        let rect = CGRect(x: 0, y: 0, width: pixelsWide, height: pixelsHigh)
        CGContextDrawImage(context, rect, img)

        return context!
    }

    func color_at(x x: Int, y: Int)->UIColor {

        assert(0<=x && x<width)
        assert(0<=y && y<height)

        let uncasted_data = CGBitmapContextGetData(context)
        let data = UnsafePointer<UInt8>(uncasted_data)

        let offset = 4 * (y * width + x)

        let alpha = data[offset]
        let red = data[offset+1]
        let green = data[offset+2]
        let blue = data[offset+3]

        let color = UIColor(red: CGFloat(red)/255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: CGFloat(alpha)/255.0)

        return color
    }
}

This is where the leak is happening.

enter image description here Does anyone know how I can fix this memory leak?

villy393
  • 2,985
  • 20
  • 28
  • you malloc memory, and then never free it. it won't be automatically freed when that method returns. in other words, you're pulling a can off a shelf, forgetting you pulled it, and just keep on pulling fresh cans. eventually you end up with nowhere to put those cans because the floor is now littered with all the previous ones. – Marc B Feb 19 '16 at 14:48
  • How do I free that memory? – villy393 Feb 19 '16 at 14:48
  • if I free the memory I get a EXC_BA_ACCESS on `CGContextDrawImage(context, rect, img)` – villy393 Feb 19 '16 at 15:07
  • If I free the memory after `CGContextDrawImage(context, rect, img)` then I get `EXC_BAD_ACCESS` on `let color = UIColor(red: CGFloat(red)/255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: CGFloat(alpha)/255.0)` – villy393 Feb 19 '16 at 15:09
  • 1
    you free it when you're done using whatever you grabbed the memory for in the first place, and that includes everything ELSE that's using the memory block. if pointers to that memory are kept around by some other part of the system, and try to use the ram after you've free()'d, it, then you're now working with a use-after-free error and that can be a major security problem. – Marc B Feb 19 '16 at 15:11
  • @MarcB Thanks. I managed to fix by adding `private class func create_bitmap_context(img: CGImage)->CGContextRef {` code into `func color_at(x x: Int, y: Int, img: CGImage)->UIColor {` so that I could `free()` the bitmapData at the end of the method – villy393 Feb 19 '16 at 15:21

0 Answers0