Terminated due to out of memory crashes

Hi,


I'm building an ios app for iPad (swift 3) and keep getting crashes with the message 'Terminated due to out of memory'. I can't seem to find a pattern on which this is caused and I've tried a lot of posible solutions but can't seem to solve it.


First, some information about my app:

  • I have zombies disabled
  • I'm testing on an iPad Air, 32Gb with 4.05Gb free.
  • The app can just crash without any other warning or message on the console but the 'terminated due to out of memory'
  • I'm not using segues at all.
  • I have 2 modules on the app, one for each role on my app (parent and child). One module uses navigation controllers and the other one doesn't.

    For the one with navigation controller I use push and pop instructions

// To go forward

let storyboard = UIStoryboard(name: "storyboardid", bundle: Bundle.main)
let viewController = storyboard.instantiateViewController(withIdentifier: "viewcontrollerid")
self.navigationController?.pushViewController(newViewController, animated: true)


// To go back
viewController.navigationController?.popViewController(animated: true)
  • For the one without navigation controller I use present (to go forward and backward) and I've tried different approaches
  • // First
    let storyboard = UIStoryboard(name: "storyboardid", bundle: Bundle.main)
    let newViewController = storyboard.instantiateViewController(withIdentifier: "viewcontrollerid")
    newViewController.transitioningDelegate = self.rightToLeftDelegate
    viewController.present(newViewController, animated: true, completion: nil)
    
    // Second
    let storyboard = UIStoryboard(name: "storyboardid", bundle: Bundle.main)
    let newViewController = storyboard.instantiateViewController(withIdentifier: "viewcontrollerid")
    newViewController.transitioningDelegate = self.rightToLeftDelegate
    viewController.present(newViewController, animated: true, completion: {
                viewController.view.window?.rootViewController = newViewController
    })
    
    // Third
    let storyboard = UIStoryboard(name: "storyboardid", bundle: Bundle.main)
    let newViewController = storyboard.instantiateViewController(withIdentifier: "viewcontrollerid")
    newViewController.transitioningDelegate = self.rightToLeftDelegate
    let parentViewController = self.getViewControllerToPresentFrom(viewController) // To ensure that only the parent presents view controllers
    parentViewController.present(newViewController, animated: true, completion: {
                parentViewController.view.window?.rootViewController = newViewController
    })
    
    fileprivate func getViewControllerToPresentFrom(_ viewController:UIViewController) -> UIViewController {
            if viewController.parent != nil {
                return self.getViewControllerToPresentFrom(viewController.parent!)
            } else {
                return viewController
            }
        }

    To set the root view controller I use the following code on AppDelegate

    // I set the root VC dynamicaly because it depends on wether it's the first time to use the app or if the user is logged in or not
    let storyboard = UIStoryboard(name: "storyboardid", bundle: Bundle.main)
    let viewController = storyboard.instantiateViewController(withIdentifier: "viewcontrollerid")
    
    window =  UIWindow(frame: UIScreen.main.bounds)
    window?.makeKeyAndVisible()
    if let window = self.window {
         inWindow.rootViewController = newViewController
    }
    • I've been using the Leaks Instrument to try to find out what is going on but can't seem to find anything or maybe I don't understand it quite well.
      • This are screenshots of the stack trace of 3 leaks found: http://imgur.com/a/tDYva
      • One is when I just open the app and do nothing, the other one is just while navigating and the third is the last one cought by the instrument before it crashed because of the 'out of memory' issue.
      • I have the leak file if any one is intrested
    • On Xcode's debug navigator, energy impact goes from zero to high and memory gets sometimes up to 450 MB (and won't go down)
    • Some view controllers get info from a web api
    let session = URLSession.shared
    let endpoint = URL(string:"http stuff")!
    let request = NSMutableURLRequest(url: endpoint)
            request.httpMethod = "GET"
            request.setValue(("application/json; charset=utf-8"), forHTTPHeaderField: "Content-Type")
            request.setValue("Basic \(TAAuthConfiguration.getToken()!)", forHTTPHeaderField: "Authorization")       
            session.dataTask(with: request as URLRequest, completionHandler: {(data:Data?, response: URLResponse?, error: Error?) in
             
                // Stuff
             
            }).resume()


    The only kind of pattern I see is that it crashes when I'm going from one view to another. Sometimes it crashed at the tenth view presented, sometimes I ned quite a long time to get it to crash.

    Somewhere I read that there was some kind of bug on the navigation controller on ios 10, could it be?


    I hope there is someone on this forum that could give me a hint as to what could be happening. I'm really lost and could use a helping hand on the matter.

    Oh and, sorry for the bad english :s I'm not english native speaker.


    Thank you

    Replies

    The Allocations instrument will be more useful than the Leaks instrument to understand what is consuming memory in your app. Minimizing your app's Memory Footprintis a good starting point.

    Hi,


    Thank you very much for the suggestion. I found out that it may have something to do with images. I still navigated through many views on this test.

    This are some screenshots of the allocation instrument result: http://imgur.com/a/LU9OI


    My app consist of a bunch of canvas (each canvas is a page of a book, presented one at a time) in which the user can drag and drop images from a catalog. They can drop as many copies of the images as they like and those images are animated (PNG that represent frames of an animation)

    I create each Image View like this:

    let imageView = UIImageView(frame: self.bounds)
    imageView.contentMode = UIViewContentMode.scaleAspectFit
    imageView.animationImages = frames //frames:[UIImage]
    imageView.animationDuration = animationDuration //animationDuration:Double
    imageView.startAnimating()


    What I can understand is that, maybe when I'm presenting the next view (in my manual navigation), the last one does not dissapear so the images are still there consuming memory. If that's the case, I can't find a way to definetly kill the view I'm leaving behind.

    Or could it be that there is another way to create the images so that it won't consume as much memory? another type of file for images with another compression to reduce the file size of each frame?


    Do you have any suggestion?