0

I am working on a web application that uses html5, css3, and jquery as the app. We run the web files through XCODE and use XCODE to upload the "apps" to iPads.

Recently we have been getting a memory warning and a crash after the splash screen spins for a few seconds.

The apps work fine in the XCODE simulator, and we have noticed that it seems to happen when the app has video files (even small ones like 800KB).

Here is the console from running the app on the iPad.

How do we prevent this crash?

Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Multi-tasking -> Device: YES, App: YES Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 kernel[0] : launchd[4020] Builtin profile: container (sandbox)

Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 kernel[0] : launchd[4020] Container: /private/var/mobile/Applications/997C5F22-C5A6-4A05-96C8-8ABEA9DAAC8A (sandbox)

Aug 15 11:50:12 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Resetting plugins due to page load.

Aug 15 11:50:15 BD-Graphics-Lab-6-iPad3 BD Push Button[4020] : Received memory warning.

Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 UserEventAgent[13] : jetsam: kernel termination snapshot being created

Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 com.apple.launchd1 (UIKitApplication:com.bd.Push.us.y[0x4721][4020]) : (UIKitApplication:com.bd.Push.us.y[0x4721]) Exited: Killed: 9

Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 backboardd[26] : Application 'UIKitApplication:com.bd.Push.us.y[0x4721]' exited abnormally with signal 9: Killed: 9

Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 ReportCrash[4021] : libMobileGestalt copySystemVersionDictionaryValue: Could not lookup ReleaseType from system version dictionary

Aug 15 11:50:17 BD-Graphics-Lab-6-iPad3 ReportCrash[4021] : Saved crashreport to /Library/Logs/CrashReporter/LowMemory-2013-08-15-115017.plist using uid: 0 gid: 0, synthetic_euid: 0 egid: 0

AppDelegate.m

@implementation AppDelegate

@synthesize window, viewController;

- (id)init
{
    /** If you need to do any extra app-specific initialization, you can do it here
     *  -jm
     **/
    NSHTTPCookieStorage* cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];

    [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];

    int cacheSizeMemory = 8 * 1024 * 1024; // 8MB
    int cacheSizeDisk = 32 * 1024 * 1024; // 32MB
#if __has_feature(objc_arc)
        NSURLCache* sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"];
#else
        NSURLCache* sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
#endif
    [NSURLCache setSharedURLCache:sharedCache];

    self = [super init];
    return self;
}

#pragma mark UIApplicationDelegate implementation

/**
 * This is main kick off after the app inits, the views and Settings are setup here. (preferred - iOS4 and up)
 */
- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    int cacheSizeMemory = 16*1024*1024; // 16MB
    int cacheSizeDisk = 32*1024*1024; // 32MB
    NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
    [NSURLCache setSharedURLCache:sharedCache];
    
    CGRect screenBounds = [[UIScreen mainScreen] bounds];

#if __has_feature(objc_arc)
        self.window = [[UIWindow alloc] initWithFrame:screenBounds];
#else
        self.window = [[[UIWindow alloc] initWithFrame:screenBounds] autorelease];
#endif
    self.window.autoresizesSubviews = YES;

#if __has_feature(objc_arc)
        self.viewController = [[MainViewController alloc] init];
#else
        self.viewController = [[[MainViewController alloc] init] autorelease];
#endif
    self.viewController.useSplashScreen = YES;

    // Set your app's start page by setting the <content src='foo.html' /> tag in config.xml.
    // If necessary, uncomment the line below to override it.
    // self.viewController.startPage = @"index.html";

    // NOTE: To customize the view's frame size (which defaults to full screen), override
    // [self.viewController viewWillAppear:] in your view controller.

    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];

    return YES;
}

// this happens while we are running ( in the background, or from within our own app )
// only valid if flush.ca.mbp-Info.plist specifies a protocol to handle
- (BOOL)application:(UIApplication*)application handleOpenURL:(NSURL*)url
{
    if (!url) {
        return NO;
    }

    // calls into javascript global function 'handleOpenURL'
    NSString* jsString = [NSString stringWithFormat:@"handleOpenURL(\"%@\");", url];
    [self.viewController.webView stringByEvaluatingJavaScriptFromString:jsString];

    // all plugins will get the notification, and their handlers will be called
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginHandleOpenURLNotification object:url]];

    return YES;
}

// repost the localnotification using the default NSNotificationCenter so multiple plugins may respond
- (void)            application:(UIApplication*)application
    didReceiveLocalNotification:(UILocalNotification*)notification
{
    // re-post ( broadcast )
    [[NSNotificationCenter defaultCenter] postNotificationName:CDVLocalNotification object:notification];
}

- (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
    // iPhone doesn't support upside down by default, while the iPad does.  Override to allow all orientations always, and let the root view controller decide what's allowed (the supported orientations mask gets intersected).
    NSUInteger supportedInterfaceOrientations = (1 << UIInterfaceOrientationPortrait) | (1 << UIInterfaceOrientationLandscapeLeft) | (1 << UIInterfaceOrientationLandscapeRight) | (1 << UIInterfaceOrientationPortraitUpsideDown);

    return supportedInterfaceOrientations;
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application
{
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    NSLog(@"Cache Cleared");
}

CDVViewController.m

- (void)didReceiveMemoryWarning
{
    // iterate through all the plugin objects, and call hasPendingOperation
    // if at least one has a pending operation, we don't call [super didReceiveMemoryWarning]

    NSEnumerator* enumerator = [self.pluginObjects objectEnumerator];
    CDVPlugin* plugin;

    BOOL doPurge = YES;

    while ((plugin = [enumerator nextObject])) {
        if (plugin.hasPendingOperation) {
            NSLog(@"Plugin '%@' has a pending operation, memory purge is delayed for didReceiveMemoryWarning.", NSStringFromClass([plugin class]));
            doPurge = NO;
        }
    }

    if (doPurge) {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
    }

    // Release any cached data, images, etc. that aren't in use.
}

- (void)viewDidUnload
{
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

    self.webView.delegate = nil;
    self.webView = nil;
    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];
}

#pragma mark UIWebViewDelegate

/**
 When web application loads Add stuff to the DOM, mainly the user-defined settings from the Settings.plist file, and
 the device's data such as device ID, platform version, etc.
 */
- (void)webViewDidStartLoad:(UIWebView*)theWebView
{
    NSLog(@"Resetting plugins due to page load.");
    [_commandQueue resetRequestId];
    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPluginResetNotification object:self.webView]];
}

/**
 Called when the webview finishes loading.  This stops the activity view.
 */
- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{
    NSLog(@"Finished load of: %@", theWebView.request.URL);
    // It's safe to release the lock even if this is just a sub-frame that's finished loading.
    [CDVUserAgentUtil releaseLock:&_userAgentLockToken];

    /*
     * Hide the Top Activity THROBBER in the Battery Bar
     */
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];

    [self processOpenUrl];

    [[NSNotificationCenter defaultCenter] postNotification:[NSNotification notificationWithName:CDVPageDidLoadNotification object:self.webView]];
    
}

LEAKS

ALLOCATIONS

enter image description here

Community
  • 1
  • 1
rjg132234
  • 590
  • 3
  • 8
  • 21
  • The simulator has a lot more memory than an actual device. Have you tried running this through Instruments? – Abizern Aug 15 '13 at 15:51
  • Yes, ran instruments, and looked for a memory leak... Nothing showed up on the leak chart. – rjg132234 Aug 15 '13 at 16:01
  • Memory issues are not just caused by leaks - try to identify what is using and holding on to memory. – Abizern Aug 15 '13 at 16:05
  • Have you tried rebooting the iPad? You can also use instruments and view all the current memory usages (activity monitor). – Mark McCorkle Aug 15 '13 at 16:05
  • Yes, I have rebooted the iPad, no affect. I believe it's apps with videos that is causing it because the apps that don't have any videos work fine. But it's very temperamental... the video apps will not work many times, then I recompile and it works, but once the app cache is emptied on the iPad, it crashes again. – rjg132234 Aug 15 '13 at 16:27

1 Answers1

0

I had an issue with my app as well using phonegap, but once we implemented this fix in the app delegate all was working perfectly. In your case since you said emptying the cache was not working, maybe you just need to specify the cache size in which case just use the (BOOL)application code below.

In the appdelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     int cacheSizeMemory = 16*1024*1024; // 16MB
    int cacheSizeDisk = 32*1024*1024; // 32MB
    NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease];
    [NSURLCache setSharedURLCache:sharedCache];
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
    [[NSURLCache sharedURLCache] removeAllCachedResponses];
    NSLog(@"Cache Cleared");
}

Additionally we used this in the CDVViewController.m to clear it every 1 second,

- (void)webViewDidFinishLoad:(UIWebView*)theWebView
{   //...
      [[NSURLCache sharedURLCache] removeAllCachedResponses];
        NSLog(@"Cache Cleared");

       [NSTimer scheduledTimerWithTimeInterval: 1.0
                                                      target: self
                                                    selector:@selector(onTick:)
                                      userInfo: nil repeats: YES];

    }

    -(void)onTick:(NSTimer *)timer {
        [[NSURLCache sharedURLCache] removeAllCachedResponses];
        NSLog(@"Cache Cleared");

    }
Jason G
  • 309
  • 3
  • 14
  • This didn't seem to work.. The first bit of code looked like it worked for a little but then also failed. I am updating my question with what my files have in them. – rjg132234 Aug 15 '13 at 18:08
  • Two things we can try, remove what you added this "int cacheSizeMemory = 16*1024*1024; // 16MB int cacheSizeDisk = 32*1024*1024; // 32MB NSURLCache *sharedCache = [[[NSURLCache alloc] initWithMemoryCapacity:cacheSizeMemory diskCapacity:cacheSizeDisk diskPath:@"nsurlcache"] autorelease]; [NSURLCache setSharedURLCache:sharedCache];" and then add this to see what the cache size is NSLog(@"Cache memory capacity = %d bytes", [[NSURLCache sharedURLCache] memoryCapacity]); NSLog(@"Cache disk capacity = %d bytes", [[NSURLCache sharedURLCache] diskCapacity]); – Jason G Aug 15 '13 at 19:02
  • Also see if this posts helps [link](http://stackoverflow.com/questions/5980636/ios-low-memory-crash-but-very-low-memory-usage) – Jason G Aug 15 '13 at 19:02
  • When I replace the first code with the second code you provided... What should I see? and Where? – rjg132234 Aug 15 '13 at 19:18
  • sorry meant to say add it in here - (void)applicationDidReceiveMemoryWarning:(UIApplication*)application { } then when your app crashes itll give you the bytes, then change your code up top, for instance mine gave me this info in the console, 013-08-15 15:01:15.577 [514:907] Cache Cleared 2013-08-15 15:01:15.578 [514:907] Cache memory capacity = 16777216 bytes 2013-08-15 15:01:15.579 [514:907] Cache disk capacity = 33554432 bytes so then i changed it to this, int cacheSizeMemory = 17*1024*1024; int cacheSizeDisk = 34*1024*1024; – Jason G Aug 15 '13 at 19:21
  • This is what came up.. Aug 15 17:01:38 BD-Graphics-Lab-7-iPad-4 BD Push Button[649] : Cache Cleared Aug 15 17:01:38 BD-Graphics-Lab-7-iPad-4 BD Push Button[649] : Cache memory capacity = 8388608 bytes Aug 15 17:01:38 BD-Graphics-Lab-7-iPad-4 BD Push Button[649] : Cache disk capacity = 33554432 bytes – rjg132234 Aug 15 '13 at 21:01
  • so yea change your code to reflect and see how your app behaves, also if you can run allocations and leaks and take a screenshot and post the link or image if you can at this point I dont think the below will completely fix it, but it will help, so your code should look like, int cacheSizeMemory = 9 * 1024 * 1024; // 9MB int cacheSizeDisk = 34 * 1024 * 1024; // 34MB – Jason G Aug 16 '13 at 13:15
  • I added the screen shots to my question above. Weird thing is that the leak showed after using the app for a minute or so, but was shown back at the first 5 seconds. – rjg132234 Aug 16 '13 at 14:36
  • so it looks like the blame is on the AudioToolBox Library, which I know nothing of unfortunately, let me do some digging. – Jason G Aug 16 '13 at 15:25
  • Thanks. Ran it again, and had more this time. Look at the third image now. – rjg132234 Aug 16 '13 at 17:27
  • oh, after running instruments and seeing all the leaks, go back to your project navigator where it shows Run (To run your app), and this time instead of running instruments (Profile) run Analyze, it should help you out Tap and hold Run then go down and chose Analyze. It will show you where and what to fix (sometimes). – Jason G Aug 16 '13 at 17:30
  • So haven't been able to figure out the problem, but have found that if I open another one of my apps and say swipe one page, then close it and open the one that has been crashing, the one that has been crashing opens up fine... Weird right? – rjg132234 Aug 19 '13 at 17:25
  • So we found workable solution, where we changed all the background images to.jpg / .gif which of course made them smaller, and seemed to allow the app to work. – rjg132234 Aug 21 '13 at 12:57
  • wow, so your whole issue was due to image sizes, ha, well glad to hear you found a work around. – Jason G Aug 21 '13 at 13:50