GeneralBlock-56 memory leak when calling loadReque

2019-02-11 00:20发布

问题:

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!

回答1:

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



回答2:

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?



回答3:

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.



回答4:

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.