Track call sites of QMacAutoReleasePools for debugging pool usage
Printing pools by calling [NSAutoreleasePool showPools] will now give a more detailed view of where the various pools in the stack were created, eg: AUTORELEASE POOLS for thread 0x1000be5c0 17 releases pending. [0x107802000] ................ PAGE (hot) (cold) [0x107802038] ################ POOL 0x107802038 [0x107802040] 0x107791c70 ^-- allocated in function: main [0x107802048] ################ POOL 0x107802048 [0x107802050] 0x1073b2e80 ^-- allocated in function: QCocoaWindow::initialize() [0x107802058] 0x107111ed0 NSCompositeAppearance [0x107802060] 0x107111ed0 NSCompositeAppearance [0x107802068] 0x107111ed0 NSCompositeAppearance [0x107802070] 0x1073bbe10 __NSCFString [0x107802078] 0x1073bbde0 _NSViewBackingLayer [0x107802080] 0x1073bc100 NSWeakObjectValue [0x107802088] 0x1073bbe40 QNSView [0x107802090] 0x1073bbe40 QNSView [0x107802098] 0x107111ed0 NSCompositeAppearance [0x1078020a0] 0x107111ed0 NSCompositeAppearance [0x1078020a8] 0x1073bbe40 QNSView [0x1078020b0] ################ POOL 0x1078020b0 [0x1078020b8] 0x1073bbe30 ^-- allocated in function: QCocoaWindow::recreateWindowIfNeeded() Change-Id: I97faf30db5835fea2f05320435b1b8c334a478d1 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
d6c474b49b
commit
6c18f86af7
@ -48,6 +48,11 @@
|
||||
#include <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <dlfcn.h>
|
||||
#include <cxxabi.h>
|
||||
#include <objc/runtime.h>
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
@ -127,22 +132,54 @@ QT_USE_NAMESPACE
|
||||
}
|
||||
@end
|
||||
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
||||
/*
|
||||
Manages a scoped auto-release pool.
|
||||
|
||||
To track autoreleases without any pools in place, such as in main()
|
||||
before the runloop has started, export OBJC_DEBUG_MISSING_POOLS=YES
|
||||
and break in objc_autoreleaseNoPool, e.g.:
|
||||
|
||||
br set -n objc_autoreleaseNoPool -c "[((NSObject*)$r14) class] == [QNSWindow class]"
|
||||
*/
|
||||
QMacAutoReleasePool::QMacAutoReleasePool()
|
||||
: pool([[NSAutoreleasePool alloc] init])
|
||||
{
|
||||
[[[QMacAutoReleasePoolTracker alloc] initWithPool:
|
||||
Class trackerClass = [QMacAutoReleasePoolTracker class];
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
void *poolFrame = nullptr;
|
||||
if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) {
|
||||
void *frame;
|
||||
if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1))
|
||||
poolFrame = frame;
|
||||
} else {
|
||||
static const int maxFrames = 3;
|
||||
void *callstack[maxFrames];
|
||||
if (backtrace(callstack, maxFrames) == maxFrames)
|
||||
poolFrame = callstack[maxFrames - 1];
|
||||
}
|
||||
|
||||
if (poolFrame) {
|
||||
Dl_info info;
|
||||
if (dladdr(poolFrame, &info) && info.dli_sname) {
|
||||
const char *symbolName = info.dli_sname;
|
||||
if (symbolName[0] == '_') {
|
||||
int status;
|
||||
if (char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status))
|
||||
symbolName = demangled;
|
||||
}
|
||||
|
||||
char *className = nullptr;
|
||||
asprintf(&className, " ^-- allocated in function: %s", symbolName);
|
||||
|
||||
if (Class existingClass = objc_getClass(className))
|
||||
trackerClass = existingClass;
|
||||
else
|
||||
trackerClass = objc_duplicateClass(trackerClass, className, 0);
|
||||
|
||||
free(className);
|
||||
|
||||
if (symbolName != info.dli_sname)
|
||||
free((char*)symbolName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
[[[trackerClass alloc] initWithPool:
|
||||
reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user