Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Termination due to memory pressure with known cause, unknown solution

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

like image 925
MattLoszak Avatar asked Oct 31 '13 15:10

MattLoszak


2 Answers

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);
like image 126
David H Avatar answered Sep 27 '22 17:09

David H


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.

like image 35
MattLoszak Avatar answered Sep 27 '22 18:09

MattLoszak