I have a simple NSCollectionView that displays a set of images, each one with a checkbox and a title under it. I've run it with the Leaks profiling tool, and it shows a few leaks. I'm trying to understand where the leaks come from, as none of my code appears in the stack trace for the leak. For example, just displaying a few items in the collection, selecting an image and dismissing the window results in 15 leaked NSMutableIndexSet objects. Most of the stack traces for these leaks look like this:
0 libsystem_malloc.dylib malloc_zone_calloc
1 libsystem_malloc.dylib calloc
2 libobjc.A.dylib class_createInstance
3 Foundation NSAllocateObject
4 AppKit -[NSCollectionViewLayoutAccessibility _visibleSections]
5 AppKit -[NSCollectionViewLayoutAccessibility _dumpVisibleChildren]
6 AppKit -[NSCollectionViewLayoutAccessibility accessibilityInvalidateLayout]
7 AppKit -[NSCollectionView layout]
8 AppKit -[NSView _doLayout]
9 AppKit -[NSView _layoutSubtreeWithOldSize:]
10 AppKit -[NSView _layoutSubtreeWithOldSize:]
11 AppKit -[NSView _layoutSubtreeWithOldSize:]
12 AppKit -[NSView _layoutSubtreeWithOldSize:]
13 AppKit -[NSView _layoutSubtreeWithOldSize:]
14 AppKit -[NSView _layoutSubtreeWithOldSize:]
15 AppKit -[NSView _layoutSubtreeWithOldSize:]
16 AppKit -[NSView _layoutSubtreeWithOldSize:]
17 AppKit -[NSView _layoutSubtreeWithOldSize:]
18 AppKit -[NSView layoutSubtreeIfNeeded]
19 AppKit -[NSWindow(NSConstraintBasedLayout) _layoutViewTree]
20 AppKit -[NSWindow(NSConstraintBasedLayout) layoutIfNeeded]
21 AppKit ___NSWindowGetDisplayCycleObserver_block_invoke6358
22 AppKit __37+[NSDisplayCycle currentDisplayCycle]_block_invoke
23 QuartzCore CA::Transaction::run_commit_handlers(CATransactionPhase)
24 QuartzCore CA::Context::commit_transaction(CA::Transaction*)
25 QuartzCore CA::Transaction::commit()
26 QuartzCore CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*)
27 CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
28 CoreFoundation __CFRunLoopDoObservers
29 CoreFoundation CFRunLoopRunSpecific
30 HIToolbox RunCurrentEventLoopInMode
31 HIToolbox ReceiveNextEventCommon
32 HIToolbox _BlockUntilNextEventMatchingListInModeWithFilter
33 AppKit _DPSNextEvent
34 AppKit -[NSApplication _nextEventMatchingEventMask:untilDate:inMode:dequeue:]
35 AppKit -[NSApplication run]
36 AppKit NSApplicationMain
37 libdyld.dylib start
My collection view data source and delegate code is fairly straightforward. I'm at a loss to understand why these are leaking. Can anyone help me understand what's going on here?
My code does allocate some NSMutableIndexSet objects, but they are autoreleased instances, so it shouldn't be leaking them. (And also, the stack trace shows that it's not coming from where my code creates them, so it doesn't seem to be related.)
If it makes any difference, I'm using ARC, building my app with Xcode 8.2.1 and running on macOS 10.11.6 (El Capitan).
One or two of the leaks do show 2 lines of my code in the stack trace. Basically, the call to my window controller's -loadWindow method shows up in the middle of the stack. The window is not deallocated when these leaks show up, so if it were anything in the window holding on to them, it would still be in memory (and hence not a leak).
It appears that this is a known leak in El Capitan that is fixed in Sierra, according to this discussion on Apple's developer forums:
I'm no longer seeing the leak in when profiling in Instruments in Xcode 8 on Sierra. It looks likey did fix it actually. Thanks Apple
Related
I have been building an app for a client and everything was going smoothly until I started getting this error. This is a unique situation, I've learned how to use instruments and NSZombie however I can't run instruments with NSZombieEnabled on the iPhone only on the simulator. I have to debug this problem in the iPhone because I'm using UIImagePicker to take a picture and the error happens shortly after I take the picture. I'm also using ARC so I can't set release or retain info at all, ARC forbids it, so I doubt its a double release or anything like that. There are 2 possible answers to this question.
1: Does anyone know if I can pass an image into UIImagePicker using photo booth? I could use instruments and NSZombie if I could get passes the camera screen.
2: Is there a way to detect what line would be causing the error without refactoring or commenting out code using the iPhone? Does anybody know an efficient way to track down bad_acces on the iPhone?
Keep in mind I am using ARC and cannot debug this on the simulator. If I take out the UIImagePicker control script the bug does not happen so I've narrowed it down to something in my CameraViewController class. I'm afraid I can't post any code due to a preexisting contract, you would have to be an employee to view source code.
Sorry about the limited information but really I'm looking for an answer about debugging not a direct solution to my exact code problem.
Going to post the backtrace(i think)
(gdb) bt
#0 0x339737e4 in objc_msgSend ()
#1 0x31b30140 in -[UIApplication sendAction:to:from:forEvent:] ()
#2 0x31b300e0 in -[UIApplication sendAction:toTarget:fromSender:forEvent:] ()
#3 0x31b300b2 in -[UIControl sendAction:to:forEvent:] ()
#4 0x31b2fe04 in -[UIControl(Internal) _sendActionsForEvents:withEvent:] ()
#5 0x31b30452 in -[UIControl touchesEnded:withEvent:] ()
#6 0x31b2eddc in -[UIWindow _sendTouchesForEvent:] ()
#7 0x31b2e756 in -[UIWindow sendEvent:] ()
#8 0x31b299fe in -[UIApplication sendEvent:] ()
#9 0x31b29336 in _UIApplicationHandleEvent ()
#10 0x3026c04a in PurpleEventCallback ()
#11 0x3443fce2 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
#12 0x3443fca6 in __CFRunLoopDoSource1 ()
#13 0x3443256c in __CFRunLoopRun ()
#14 0x34432276 in CFRunLoopRunSpecific ()
#15 0x3443217e in CFRunLoopRunInMode ()
#16 0x3026b5f2 in GSEventRunModal ()
#17 0x3026b69e in GSEventRun ()
#18 0x31ad0122 in -[UIApplication _run] ()
#19 0x31ace12e in UIApplicationMain ()
#20 0x000034ce in main (argc=1, argv=0x2ffff75c) at /Users/Andrew/Documents/Developing/Xcode Projects/ProjectSVN/Project/trunk/ProjectInterface/ProjectInterface/main.m:16
EXC_BAD_ACCESS doesn't necessarily mean a memory management problem. It could just as easily be caused by memory corruption or other kinds of errors.
Post the backtrace of the crash.
Without code samples it is hard to say, however ARC doesn't totally cover all of your bases. For example, it is possible to get these EXC_BAD_ACCESS errors when objects (classes with delegates) do not exist, yet try to execute callback delegate methods.
To be more specific, let's say I have created a class in viewDidLoad: - let's call it ClassA. In my hypothetical situation, I set my view controller to ClassA's delegate. However, I have not declared a property for ClassA, so there is no reference to it beyond the scope of viewDidLoad:.
Now let's assume ClassA declare a delegate method that is implemented by my view controller. This delegate passes a reference of itself back to the view controller in this delegate method. Because it may or may not be out of scope by this point, BOOM, bad access error. Check for things such as this, where objects do not exist anymore and are being passed to other methods - it is one such way ARC can fail you ;)
I get invariably this error when I close the last window of my app:
Application Specific Information: objc_msgSend() selector name:
respondsToSelector: objc[42729]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0
libobjc.A.dylib 0x00007fff8cc9a150 objc_msgSend_vtable5
+ 16 1 com.apple.AppKit 0x00007fff8fbca814 -[NSApplication supplementalTargetForAction:sender:] + 63 2 com.apple.AppKit 0x00007fff8fab91e4
_objectFromResponderChainWhichRespondsToAction + 155 3 com.apple.AppKit 0x00007fff8fab8feb
_NSTargetForSendAction + 3255 4 com.apple.AppKit 0x00007fff8fab832f -[NSApplication targetForAction:to:from:] + 682 5
com.apple.AppKit 0x00007fff8fab7e00 -[NSMenu
_enableItem:] + 403
I confess that the document nib has two windows. I want the "auxiliary window" to be closed and deallocated when the main window is closed. How should I do? Maybe these errors com from hereā¦ I'm using Core Data and ARC.
Regards
I found something which seems to solve the problem. But I don't understand what's happening and I really dislike this.
In IB, the file's owner has a "window" outlet who points to the document window; but there is no #property NSWindow window; in the default code of the NS(Persistent)Document.
I had to make a panel a "child window" of the doc's main window, so I add a #property NSWindow mainWindow. The new "mainWindow" outlet points to the same window as the "window" outlet.
And suddenly no more crash, no more zombie. What happened? I'm baffled.
After reflexion: I have added a pointer to the document window, so the ARC counter never reaches zero. I suppose I had a missing reference somewhere to the _window of the NSDocument, which is now balanced by my outlet.
The Problem
I'm receiving crash reports from users that look like this:
Code Type: X86-64 (Native)
Parent Process: launchd [223]
Date/Time: 2012-03-22 11:28:33.087 +0800
OS Version: Mac OS X 10.7.3 (11D50)
Report Version: 9
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: 0x000000000000000d, 0x0000000000000000
VM Regions Near 0:
-->
__TEXT 000000010c202000-000000010c29c000 [ 616K] r-x/rwx SM=COW /Applications/CodeKit.app/Contents/MacOS/CodeKit
Application Specific Information:
objc_msgSend() selector name: release
objc[22113]: garbage collection is OFF
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff904f5390 objc_msgSend_vtable14 + 16
1 com.apple.Foundation 0x00007fff8f664137 empty + 61
2 com.apple.Foundation 0x00007fff8f666c10 dealloc + 24
3 com.apple.Foundation 0x00007fff8f666bd1 -[NSConcreteMapTable dealloc] + 64
4 com.apple.AppKit 0x00007fff892bc52c -[_NSDisplayOperation dealloc] + 84
5 com.apple.CoreFoundation 0x00007fff8fdc7ca0 CFRelease + 176
6 com.apple.CoreFoundation 0x00007fff8fdf0742 -[__NSArrayM removeObjectAtIndex:] + 434
7 com.apple.AppKit 0x00007fff892bc408 -[_NSDisplayOperationStack exitDisplayOperationForWindow:] + 417
8 com.apple.AppKit 0x00007fff892be2fc -[NSView _displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] + 7136
9 com.apple.AppKit 0x00007fff892b6429 -[NSView displayIfNeeded] + 1676
10 [SEE DISCUSSION BELOW]
Discussion
Lines 10 and below vary wildly between reports (and hence are unrelated to the crash). However, the sequence from lines 1 to 9 is always the same. Every crash contains this exact sequence. I've googled "_NSDisplayOperationStack" and I've found similar crash reports for dozens of apps (including well-known ones such as Omni apps and Apple's Motion.)
What I Need
Because the crash is coming from Core Foundation, I have no idea where to begin looking for the problem. It seems to be deep inside Cocoa's private view-drawing machinery. Worse still, I can't replicate the crash on my machine at all, so I can't trace it with Instruments. But I've received many reports with the pattern above, so I know it's a problem. Worse STILL, the users can't even reproduce the crash reliably -- it's completely intermittent.
I'm hoping the above sequence looks familiar to someone and they can give me guidance on where to start looking for the problem. Thank you.
I posted this same question over at the Apple Developer forums and one engineer told me that it looked like the stack trace had to do with concurrent view drawing, which is a feature that was introduced in 10.6.
I went through all of my NIB files and found two NSButton instances that were set to draw concurrently --- this was not intentional; I must have checked that box by accident at some point.
I disabled the concurrent drawing for both of them and this crash has magically disappeared.
In some cases disabling concurrent drawing for just some buttons doesn't help. I got the same error as the author's ("_NSDisplayOperationStack underflow raised during heart beat."). Lucky there is a master switch in a window that disables all concurrent drawing for one window:
[self.window setAllowsConcurrentViewDrawing:NO];
Also opening the the window via a block executed on the main queue helped:
dispatch_async(dispatch_get_main_queue(), ^{
if(nil == self.someWindowController) {
self.someWindowController = [[[SomeWindowController alloc] initWithWindowNibName:#"SomeWindowController"] autorelease];
}
[self.someWindowController.window makeKeyAndOrderFront:self];
});
Showing the window from within a block just postpones the execution a little bit but for my application, some additional window opening via menu shortcut, a combination of the two were the only thing working.
I recently received a crash report from itunes connect. Actually it's the only crash report I got from thousands of users, yet. It's an iPod4,1 device. Interesting parts are:
Date/Time: 2012-02-27 22:53:27.596 +0800
OS Version: iPhone OS 5.0.1 (9A405)
Report Version: 104
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x00000000, 0x00000000
Crashed Thread: 0
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
It seems that the crash occurs when a row from a table view is selected, and a new view controller is pushed into navigation. According to my code, the new view controller is created already, so the crash occurred in UINavigationController.
It doesn't look like the fault of the code I wrote. And I wonder if I'm correct on this? How do I debug this problem?
It sounds like the user got a low-memory warning. UINavigationControllers will retain their views, whereas tabbed ones will pop off the invisible ones. However, the low memory code is still getting called. Check your warning handlers prior to reaching that spot. Also, test by hitting "Simulate Memory Warning" under the hardware menu at all entry and exit points.
http://forums.macrumors.com/showthread.php?t=876419 shows a mess of what happens when you don't.
iphonedevsdk.com/forum/iphone-sdk-development/14225-uinavigationcontrollers-and-didreceivememorywarning.html has a nice comment or so on how to handle this.
I'm betting your view controller loads something and caused the memory warning. Ensure the user can't just stack tons of items on top of each other, and make sure your app is profiled to remove as many leaks as necessary to keep the app up.
The above may not be on the mark, but should be related.
Final note, don't use ARC. Something that disallows calling superclass functions is bound to screw up. If you understand bridging Core Foundation, then perhaps ARC is fine. I personally avoid it at all costs b/c memory becomes randomly handled by Apple's under-the-hood. I've seen their stuff fail way too much
I got it! I had the same problem too and in your code it looks like that a button is pressed, which causes the crash!
Last Exception Backtrace:
0 CoreFoundation 0x338958bf __exceptionPreprocess + 163
1 libobjc.A.dylib 0x303891e5 objc_exception_throw + 33
2 UIKit 0x31259749 -[UIViewController mutableChildViewControllers] + 1
3 UIKit 0x31259349 -[UINavigationController pushViewController:animated:] + 37
4 MyApp 0x000081e5 -[MyListController tableView:didSelectRowAtIndexPath:] (MyListController.m:207)
5 UIKit 0x312d3565 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 945
6 UIKit 0x3134bce7 -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 159
Here is my suggestion:
Two things to solve a SIGABRT:
1) SIGABRT happens due to a runtime exception that isn't caught. When this happens there is some info written to the debugger console or the device console that explains the exact reason for the exception. You haven't shown us this text. It starts "Terminating application due to ..."
Show us that text.
2) If you run your app in the debugger and set a breakpoint on the exception throw function the app will stop when the exception is thrown and this will usually be enough to figure it out. Go to the debugger breakpoint pane and at the bottom left is a control that when clicked allows you to set an exception breakpoint.
A user has sent in a crash report with the stack trace listed below (I have not been able to reproduce the crash myself, but every other crash this user has reported has been a valid bug, even when I couldn't reproduce the effect). The application is a reference-counted Objective-C/Cocoa app.
If I am interpreting it correctly, the crash is caused by attempting to send a drawerDidOpen: message to a deallocated object. The only object that should be receiving drawerDidOpen: is the drawer's delegate object (nowhere does any object register to receive drawer notifications), and the drawer's delegate object is instantiated via the XIB/NIB file, wired to the delegate outlet of the drawer, and not referenced anywhere else.
Given that, how can I protect against the delegate getting dealloc'd before the drawer notification? Or, alternately, what have I misinterpreted that might be causing the crash?
Crash log/stack trace:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Application Specific Information:
objc_msgSend() selector name: drawerDidOpen:
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 libobjc.A.dylib 0x00007fff8272011c objc_msgSend + 40
1 com.apple.Foundation 0x00007fff87d0786e _nsnote_callback + 167
2 com.apple.CoreFoundation 0x00007fff831bcaea __CFXNotificationPost + 954
3 com.apple.CoreFoundation 0x00007fff831a9098 _CFXNotificationPostNotification + 200
4 com.apple.Foundation 0x00007fff87cfe7d8 -[NSNotificationCenter postNotificationName:object:userInfo:] + 101
5 com.apple.AppKit 0x00007fff8512e944 _NSDrawerObserverCallBack + 840
6 com.apple.CoreFoundation 0x00007fff831d40d7 __CFRunLoopDoObservers + 519
7 com.apple.CoreFoundation 0x00007fff831af8c4 CFRunLoopRunSpecific + 548
8 com.apple.HIToolbox 0x00007fff839b8ada RunCurrentEventLoopInMode + 333
9 com.apple.HIToolbox 0x00007fff839b883d ReceiveNextEventCommon + 148
10 com.apple.HIToolbox 0x00007fff839b8798 BlockUntilNextEventMatchingListInMode + 59
11 com.apple.AppKit 0x00007fff84de8a2a _DPSNextEvent + 708
12 com.apple.AppKit 0x00007fff84de8379 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 155
13 com.apple.AppKit 0x00007fff84dae05b -[NSApplication run] + 395
14 com.apple.AppKit 0x00007fff84da6d7c NSApplicationMain + 364
15 (my app's identifier) 0x0000000100001188 start + 52
edit: To clarify: This crash happened once in thousands or maybe tens of thousands of virtually-identical usage scenarios. I don't retain/release/alloc/dealloc/anything-memory-management the delegate object anywhere in my code; I don't register any object for any drawer notifications of any kind in my code; my code has no variables (nor ivars) pointing to the delegate object.
What it looks like to me is that when the NIB was unloaded (as in whatever the Cocoa system does when the document window gets closed), somehow the drawer's delegate object was dealloc'd before the drawer object itself, but the Cocoa system is supposed to prevent that from happening (and seems to handle it correctly in the vast majority of cases).
The delegate has been released to the point of deallocation without first being unregistered from the notification center (in this case, the delegation is through the notification center, not directly).
An easy fix is to call NSNotificationCenter's -removeObserver: method from your delegate's -dealloc method.
Check the backtrace -- it is through the notification center that the crash happens. Most likely, when the class is connected via setDelegate: (via the NIB file), it is done so as a notification observer.
Regardless, the relationship between notification center and your object is the same as between the object in IB and your object; weak. That is, there is no retain and, thus, your delegate is being freed too early (or, alternatively, you are over-releasing the object somewhere).
In any case, you need to make sure your delegate is retained by something somewhere for the duration of its usefulness.