I'm working on an IPad app and have been profiling it using Instruments in XCode 4.
I'm profiling on the actual device itself. iOS 4.3 is installed.
Instruments tells me I have some memory leaks, the leaked objects being mainly GeneralBlock-56
ones and some GeneralBlock-1024
/GeneralBlock-8192
ones.
The interesting thing is that these leaks are reported only when I load up a URL in a UIWebView embedded in my app. If I comment out the loadRequest
call, these leaks go away. This behavior is consistently reproducible.
The loadRequest() calls looks like this:
[webPage loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://slashdot.org"]]];
I'm not specifying any delegates for this UIWebView, by the way.
The leaks do not show any Responsible Library/Responsible Frame and there is no Extended Detail in the rightmost frame.
I have tried to fiddle around with the NSURLCache settings, like so:
NSURLCache *sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
[sharedCache release];
This reduces a few of the GeneralBlock memory leaks, but some still remain.
Any insights on this behavior are very welcome...thanks!
This is a bug report I filed with the Apple Developer Bug Reporting tool. This seemed to be one of the big issues causing the memory leak in my case.
Summary: Passing incorrectly formatted NSURL to NSData dataWithContentsOfURL: causes memory leak in createCanonicalURL() method.
Steps to Reproduce
In any simple project, put the following lines in your controller, for example, in loadView: or viewDidLoad: methods.:
NSURL* u = [NSURL URLWithString:@"http:/portalqa01:70/Images/Leading%20out%20of%20a%20Downturn%20-%20Article%20Illustration%20-%20Large_tcm137-38905.gif"];
NSData* data = [NSData dataWithContentsOfURL:u options:0 error:nil];
Note that the URL has only a single slash after "http:" instead of the customary two.
Expected Results: There shouldn't be any memory leak.
Actual Results: Instruments shows a memory leak.
Regression:
This only occurs for some malformed URLs, the URL above is a specific example. A URL like "http:/blah/blah.png" will not cause a leak.
The environments used to reproduce this were:
- iPad 4.3 Simulator
- iPad 2 with iOS 4.3.1
Notes:
The stack trace is as below:
STACK TRACE START
0 CFNetwork createCanonicalURL
1 CFNetwork HTTPProtocol::_createMutableCanonicalRequest(__CFAllocator const*, _CFURLRequest const*, void const*)
2 CFNetwork HTTPProtocol::_createCanonicalRequest(__CFAllocator const*, _CFURLRequest const*, void const*)
3 CFNetwork HTTPProtocol::copyCanonicalRequest()
4 CFNetwork URLConnectionLoader::copyProtocolCanonicalRequest()
5 CFNetwork URLConnectionClient::getRequestForTransmission(unsigned char, _CFURLResponse*, _CFURLRequest const*, __CFError**)
6 CFNetwork URLConnectionClient::_clientWillSendRequest(_CFURLRequest const*, _CFURLResponse*, URLConnectionClient::ClientConnectionEventQueue*)
7 CFNetwork URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload(XConnectionEventInfo<XClientEvent, XClientEventParams>*, long)
8 CFNetwork URLConnectionClient::processEvents()
9 CFNetwork MultiplexerSource::perform()
10 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__
11 CoreFoundation __CFRunLoopDoSources0
12 CoreFoundation __CFRunLoopRun
13 CoreFoundation CFRunLoopRunSpecific
14 CoreFoundation CFRunLoopRunInMode
15 CFNetwork CFURLConnectionSendSynchronousRequest
16 Foundation +[NSURLConnection sendSynchronousRequest:returningResponse:error:]
17 Foundation -[NSData(NSData) initWithContentsOfURL:options:error:]
18 Foundation +[NSData(NSData) dataWithContentsOfURL:options:error:]
19 MemLeakTester -[MemLeakTesterViewController viewDidLoad] /Users/admin/IPadSpikes/MemLeakTester/MemLeakTester/MemLeakTester/MemLeakTesterViewController.m:36
20 UIKit -[UIViewController view]
21 UIKit -[UIWindow addRootViewControllerViewIfPossible]
22 MemLeakTester -[MemLeakTesterAppDelegate application:didFinishLaunchingWithOptions:] /Users/admin/IPadSpikes/MemLeakTester/MemLeakTester/MemLeakTester/MemLeakTesterAppDelegate.m:27
23 UIKit -[UIApplication _callInitializationDelegatesForURL:payload:suspended:]
24 UIKit -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:]
25 UIKit -[UIApplication handleEvent:withNewEvent:]
26 UIKit -[UIApplication sendEvent:]
27 UIKit _UIApplicationHandleEvent
28 GraphicsServices PurpleEventCallback
29 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
30 CoreFoundation __CFRunLoopDoSource1
31 CoreFoundation __CFRunLoopRun
32 CoreFoundation CFRunLoopRunSpecific
33 CoreFoundation CFRunLoopRunInMode
34 UIKit -[UIApplication _run]
35 UIKit UIApplicationMain
36 MemLeakTester main /Users/admin/IPadSpikes/MemLeakTester/MemLeakTester/MemLeakTester/main.m:14
37 MemLeakTester start
STACK TRACE END
I am experiencing the same issue. I am still trying to verify this, but my initial observation is that it only occurs with sites that are serving javascript. Have you observed this pattern?
Try adding
[webView loadHTMLString: @"" baseURL: nil];
right before you release the webview. For a leak in 4.2.1 relating to displaying a PDF in a UIWebView this solves most of the leak problems for me.
Well, I had the same issue with UIWebView - a whole bunch of leaks (General-Block56 etc) on iPad, iPad2, iPhone. Finally the following helped: reject the Nib-file and the method 'viewDidLoad'. Instead of this I've created the webview in 'loadView' programmatically:
- (void)loadView
{
self.activityView = [[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray] autorelease];
self.webView = [[UIWebView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
[self.webView addSubview: self.activityView];
self.webView.scalesPageToFit = YES;
self.view = self.webView;
[self addGestures];
}
- (void)viewWillAppear:(BOOL)animated
{
self.webView.delegate = self;
[self.webView loadRequest:[self urlRequest]];
[super viewWillAppear:animated];
}
At the end there's only one small leak remaining (16 bytes) right after start loading the very first page. All other pages did load without any leak. Hope this helps.