Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective C UIImagePNGRepresentation memory issue (using ARC)

I have an ARC based app which loads about 2,000 fairly large (1-4MB) Base64 encoded images from a webservice. It converts the Base64 decoded strings to .png image files and saves them to the disk. This is all done in a loop where i shouldn't have any lingering references.

I profiled my app and found out that UIImagePNGRepresentation was hogging around 50% of available memory.

The way i see it, UIImagePNGRepresentation is caching the images it creates. One way to fix this would be to flush that cache. Any ideas how one might do that?

Another solution would be to use something other than UIImagePNGRepresentation?

I already tried out this with no luck: Memory issue in using UIImagePNGRepresentation. Not to mention that i can't really use the solution provided there 'cause it would make my app too slow.

This is the method i call from my loop. UIImage is the image converted from Base64:

+ (void)saveImage:(UIImage*)image:(NSString*)imageName:(NSString*)directory {
  NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it
  NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory
  NSString *pathToFolder = [documentsDirectory stringByAppendingPathComponent:directory];

  if (![fileManager fileExistsAtPath:pathToFolder]) {
    if(![fileManager createDirectoryAtPath:pathToFolder withIntermediateDirectories:YES attributes:nil error:NULL]) {
       // Error handling removed for brevity
    }
  }

  NSString *fullPath = [pathToFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path
  [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image)

  // clear memory (this did nothing to improve memory management)
  imageData = nil;
  fileManager = nil; 
}

EDIT: Image dimensions vary roughly from 1000*800 to 3000*2000.

like image 784
JHollanti Avatar asked Mar 19 '12 22:03

JHollanti


1 Answers

You could wrap the method body by a autorelease pool

+ (void)saveImage:(UIImage*)image:(NSString*)imageName:(NSString*)directory {

    @autoreleasepool
    {
        NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format.
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it
        NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory
        NSString *pathToFolder = [documentsDirectory stringByAppendingPathComponent:directory];

        if (![fileManager fileExistsAtPath:pathToFolder]) {
          if(![fileManager createDirectoryAtPath:pathToFolder withIntermediateDirectories:YES attributes:nil error:NULL]) {
             // Error handling removed for brevity
          }
        }

        NSString *fullPath = [pathToFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path
        [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image)
    }
}

But actually it could be helpful, if you provide us with some more numbers:
What dimensions do the images have. This is important, as image data is stored in memory in raw pixels. iE a image 2000px width * 2000px height * 4 Bytes (RGBA) ~ 15MB. Now imagine, that the converting algorithm will have to store informations for every pixel or at least some area. Huge numbers are to be expected.

like image 70
vikingosegundo Avatar answered Sep 20 '22 07:09

vikingosegundo