6

My app, which uses ARC, does the following:

  1. Uploads a picture taken by the camera
  2. Compresses the picture for use as a thumbnail.
  3. I do this using [UIImage imageWithData:UIImageJPEGRepresentation( original, 0.1f )]
  4. I set the uncompressed picture reference to nil for ARC to free the memory

Repeating this sequence will mean that several compressed thumbnails are on the screen. After about 7 or 8 pictures, the app wil crash due to low memory.

In Instruments, I am attempting to use Allocations in tandem with Memory Monitor to find the source of my problem.

Some Instruments stats:

Allocation - Live Bytes jumps by about 2 MB after taking a picture, but then goes down by 1.5 MB after original picture reference is set to nil. That seems to be a good thing, but...

Here's an eventual state of the application. #Living seems to be very high relative to the Live Bytes, right?

  Live Bytes  #Living   #Transitory  Overall   #Overall Bytes    
   3.72 MB    24538     80679        90.1 MB   105301

Memory Monitor (tracking inspection head) - My application starts up at 7.5 MB and taking one picture results in that increasing by ~13 MB. For the state that I listed above, Memory Monitor says that the app is taking up 72.67 MB of "Real Memory" and 123.79 MB of Virtual Memory.

Given that the Live Bytes are very small, I know I'm doing something right. However, given that the memory footprint in other places is large, I'm also sure I'm doing something very wrong. Any ideas what that might be, or how to track it down?

Eitan
  • 1,308
  • 3
  • 15
  • 32
  • +1 for a good question. How are you loading your images to display on screen? Are you using `[UIImage imageNamed:]`? – Rog Jan 12 '12 at 01:27
  • What it the purpose of this line? [UIImage imageWithData:UIImageJPEGRepresentation( original, 0.1f )] You are compressing the image and then immediately decompressing it. The result is just a waste of picture-quality and CPU-time. – Dominik Seibold Jan 12 '12 at 02:01
  • @DominikSeibold I compress the image to reduce memory, then change it to a UIImage so I can use it as the background of a thumbnail button. – Eitan Jan 12 '12 at 10:18
  • 1
    Images are not stored in memory in their compressed state, so re-compressing them as JPEGs doesn't really gain you anything. The most important thing you can do for your images is to resize and crop the images into thumbnails that have no more pixels in them than you'll need for display. The Allocations instrument [hides some memory usage that Memory Monitor shows](http://stackoverflow.com/a/5627221/19679), including the total in-memory size of images, so you can't rely on its Live Bytes readout for the true story here. – Brad Larson Jan 13 '12 at 17:12

2 Answers2

2

Eitan27,

This is not an ARC problem. This is about how to manage multiple large items in memory. iOS has several mechanisms to help you here. If you write the image to flash and then reopen it as memory mapped data, you will mostly solve your problem. How? The OS manages the mapping into your resident memory footprint with immutable data. Because these items are immutable and, hence, never dirty, it can then flush the mapped pages when necessary. The downside of this mechanism is the limited number of file descriptors available to each app.

Andrew

adonoho
  • 4,339
  • 1
  • 18
  • 22
  • Thanks adonoho. Your answer sounds great, though you mention a few things that I'm a bit unfamiliar with. Why is there a limit on file descriptors? By saving to flash, do you mean writing/retrieving it from the disk using a filename? Or are you more or less suggesting that I implement something similar to a TileView/CATileLayer. – Eitan Jan 15 '12 at 23:54
  • Eitan27, Every app has a limited number of files it can have open at any one time. The file descriptor is the data structure rationed by the OS. Typically, you only have 30 or so of these available. By flash, I mean your persistent storage. As you are having this space problem I just assumed you were running on iOS. All iOS devices use flash RAM as their persistent storage. Andrew P.S. Don't forget to reward the folks who answer your questions with the big green check mark. – adonoho Jan 16 '12 at 23:29
  • Absolutely, and yes I am running on iOS. I was unclear about whether the file descriptor limit is on total files, or files being open at a given time. It seems that it is the latter, and that the issue will be resolved by using a CATileLayer for opening/displaying images only as they are needed. – Eitan Jan 17 '12 at 10:44
0

Use an @autoreleasepool block:

@autoreleasepool {
    //code that inits the UIImage and sets it to nil
}

See ARC Provides a New Statement to Manage Autorelease Pools section of Transitioning to ARC Release Notes

Ben S
  • 68,394
  • 30
  • 171
  • 212
  • I'm not sure this applies to me. The image gets allocated, and then an instance of my uploader class is given a reference to the image and uploads it. The uploader then sets its reference to nil. Thus, the "init" of the image and the "sets it to nil" happen in two different places. – Eitan Jan 12 '12 at 12:42