swiftmemory-leaksuiimageuiimagejpegrepresentation

Swift UIImage .jpegData memory leak issue


I have some code that accepts a UIImage in and saves that image to disk. This code is iterated over for multiple images. I noticed that for each time the code runs, I have a memory leak that persists until the view is removed.

I tracked the issue down to the following line : var data = image.jpegData(compressionQuality: 0.8 )

Each time this line is called, the corresponding amount of memory is allocated for the compressed image (~10 Mb each time), and does not release until the view is closed. I have even tried to remove any usage of the data as well (ie the refcount should be 0), but it still does not release the memory.

    func save_to_folder( tray_number: Int64, tray_type: String, image: UIImage, filename: String ) -> Bool {
        let dir = self.directory!
            .appendingPathComponent( "trays" )
            .appendingPathComponent( String( format: "tray_%04d", tray_number ) )
            .appendingPathComponent( tray_type )
        
        print( "  save_dir: \( dir.path )" )
        
        let full_filename = dir.appendingPathComponent( filename ).appendingPathExtension( "JPG" )
        print( "  full_filename: \( full_filename.path )" )
        
        do {
            try FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true, attributes: nil )
        }
        catch let error {
            print( "Error creating directory: \( error )" )
            return false
        }
        
        var data = image.jpegData(compressionQuality: 0.8 )
        /*
        do {
            try data!.write(to: full_filename, options: Data.WritingOptions.atomic )
            return true
        }
        catch let error {
            print( "Failed to write file: \( error )" )
        }
        
        data = nil
 */
        return false
    }
for itt in 0...self.URLs.count - 1{
                let closure = { [weak self] in
                    print(self!.URLs[itt])
                    let image = UIImage.init(contentsOfFile: self!.URLs[itt].relativePath)
                    //temp_bore = try! Borehole(sqlite_filename:self!.borehole!.filename)
                    let _ = self?.borehole?.save_to_folder(tray_number: tray_number, tray_type: tray_type, image: image! )
                    tray_number += 1
                    progress += 1
                    DispatchQueue.main.async {
                        alertView.message = "Adding \( progress ) of \( total )"
                    }
                }
                closure()
            }

Does anyone know what is happening here? Why does the memory allocated by jpegData never release? Memory leak on profiler

Leak in code


Solution

  • I found the solution thanks to El Tomato.

    If anyone else runs into this issue, add autoreleasepool around your .jpegData call.

    autoreleasepool{
                let data = image.jpegData(compressionQuality: 0.8 )
        
                do {
                    try data!.write(to: full_filename, options: Data.WritingOptions.atomic )
                }
                catch let error {
                    print( "Failed to write file: \( error )" )
                }
    
            }