7

My app is terminating due to memory pressure at a certain point in the app's use, and I have isolated the problem down to one chunk of code that is causing the problem.

I'll copy the code chunk below, but first I'll describe what it's doing.

The Description:

I have a for loop that is iterating through a list of videos. For each video, the for loop increases the size of the containing scrollview, draws a label and a button (both pertaining to the video), and asynchronously grabs a thumbnail of the video and places it below the button.

The Problem:

The grabbing the thumbnail part is the problem. I don't think that the fact that this is done asynchronously is the problem, as I have tried it synchronously and the termination still occurs. When I comment out the code that grabs the thumbnail (the entire asynchronous part in the code below) the app doesn't crash.

The Code:

NB: I'm using comments to replace code in some cases for brevity.

for (int i = [_videoURLs count]-1; i >= 0 ; i--)
    {
        //increase the scrollview size

        //get background image:
        dispatch_async(screenshotQueue, ^{

            AVURLAsset *as = [[AVURLAsset alloc] initWithURL:currentURL options:nil];
            AVAssetImageGenerator *ima = [[AVAssetImageGenerator alloc] initWithAsset:as];
            ima.appliesPreferredTrackTransform = YES;
            NSError *err = NULL;
            CMTime time = CMTimeMake(1, 24);
            CGImageRef imgRef = [ima copyCGImageAtTime:time actualTime:NULL error:&err];
            UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imgRef];

            dispatch_async(dispatch_get_main_queue(), ^{

                UIImageView *backgroundImage = [[UIImageView alloc]initWithFrame:buttonFrame];
                backgroundImage.image = thumbnail;
                backgroundImage.layer.opacity = 0;
                [self.videoScrollView addSubview:backgroundImage];

                [self.videoScrollView sendSubviewToBack:backgroundImage];

                [UIView animateWithDuration:0.5 delay:0.0 options: UIViewAnimationOptionCurveEaseInOut
                 animations:^{
                     backgroundImage.layer.opacity = 1;
                 }
                 completion:^(BOOL finished){}];

            });

        });

        //add title to the screen caps

        //draw the button

    }

I'm on Xcode 5, testing on a new device with iOS 7. I'm self taught, so I'm sure I've picked up my fair share of bad habits, but I'm hoping I've missed something obvious that someone with a little more experience will pick up on.

I've tried a fair amount of googling and searching on stack overflow, and have tried looking at diagnostics, logs and memory profiles to isolate the problem further, to no avail.

Any help would be greatly appreciated!

Edit:

How to reproduce the error:

  1. Go to video list
  2. Leave video list
  3. Repeat 1+2 4 or 5 times causes the crash

Step 2. simply removes the entire scrollView from its superview and then redraws it. I understand it's not necessary to redraw the video list every time you go back to it, but I'm doing this for a certain reason and I don't believe this is the source of the problem (I could be wrong).

Edit 2:

Here's an image of the memory profile: enter image description here

MattLoszak
  • 585
  • 2
  • 5
  • 15
  • Run the app through the Allocations section of Instruments. Find which objects or block of memory are growing unexpectedly and look into their history to see what isn't releasing the memory/objects. – rmaddy Oct 31 '13 at 16:00
  • You may be adding too many thumbnail images to the scrollview. Remember that those are all stored in memory. Do you see the problem fairly consistently after adding a certain number of thumbnail images? – Peter Cetinski Oct 31 '13 at 16:03
  • @rmaddy I've tried running the allocations instrument, and the confusing thing is that the graph doesn't appear to increase as I trigger the crash. I'll attach a screenshot in another comment – MattLoszak Oct 31 '13 at 16:10
  • @PeterCetinski you're right that the problem occurs faster with more videos in the list. But I've only got 13 videos in it right now, which doesn't seem like a lot. I'll update my question with exactly how I reproduce the error – MattLoszak Oct 31 '13 at 16:12
  • Related: http://stackoverflow.com/questions/19203790/is-it-possible-to-debug-terminated-due-to-memory-error – Andrew Jan 07 '14 at 04:18

2 Answers2

13

The code you show has a huge leak. You are creating a Core Foundation object with:

CGImageRef imgRef = [ima copyCGImageAtTime:time actualTime:NULL error:&err];

yet I see no corresponding CFRelease.

You code should be:

CGImageRef imgRef = [ima copyCGImageAtTime:time actualTime:NULL error:&err];
UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imgRef];
CFRelease(imgRef);
David H
  • 40,852
  • 12
  • 92
  • 138
  • D'Oh, that was it. I was hoping it would be something so simple! Any idea why this didn't show up in the instrument output image I attached to the question? – MattLoszak Nov 01 '13 at 13:55
  • 1
    Everytime I try using Instruments I come away in tears - well not actually real tears, virtual tears. Instruments is on my bucket list of technologies to master someday. I watched the WWDC session on it a few days ago - from 2012 or 2011 - and "cried" some more as the presenter hyper jumped all over the window... – David H Nov 01 '13 at 14:24
  • 3
    You can also use the equivalent `CGImageRelease(imgRef)`. – Ja͢ck Nov 25 '14 at 09:45
  • @Ja͢ck yes a better choice as it tests for nil. – David H Nov 25 '14 at 13:21
2

Alright, so I found a decent solution. I'm still not entirely sure why this was a problem in the first place, but I have some suspicions.

I believe that the process of generating a thumbnail was just too intensive to do repeatedly on a thread over a for loop. I had this hunch, and so decided to adjust the above code. Instead of generating a new thumbnail each time, I would save newly generated screenshots as a png to the documents home directory. Then next time, I would load this resource from there. This caused the memory issues to vanish.

I hope this helps someone with a similar problem - and if someone has anything to add or a better answer is out there, I'm all ears.

MattLoszak
  • 585
  • 2
  • 5
  • 15