summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2017-04-20 18:02:16 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2017-05-08 11:01:39 +0000
commit4a5a4245b7f24b53847e96f1eee5445bdae537e6 (patch)
treec9c4d42fc00df2cd9e12dd2a9224db28b31c70b8
parenta6f3bb21e3cfcbd8ba3356fb509b465041c35858 (diff)
macOS: Add root level NSAutoreleasePool for objects autoreleased in main()
Any objects directly or indirectly autoreleased in main(), before we start the event loop, will never be released, as there are no pools present yet. This includes all resources allocated during application and window setup, unless those function have local pools. Ideally that setup code would be called from within the runloop callstack, where there is a pool present, but that requires a new main/startup-API for Qt. To aid in debugging object ownership and hierarchies within Qt, we set up our own root level pool tied to QApplication, which ensures that most objects autoreleased in main() will eventually be released and have their dealloc methods called. The feature can be disabled by setting an environment variable: QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL=1 Combined with OBJC_DEBUG_MISSING_POOLS=YES, this allows breaking on the function objc_autoreleaseNoPool to weed out codepaths in Qt that should have local pools. Change-Id: Id02e1edaaaeaa04c53862d7228e519214c99ab51 Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
-rw-r--r--src/corelib/kernel/qcore_mac_objc.mm39
-rw-r--r--src/corelib/kernel/qcore_mac_p.h13
-rw-r--r--src/corelib/kernel/qcoreapplication_p.h8
3 files changed, 60 insertions, 0 deletions
diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm
index a91c02f54e..272d6179d1 100644
--- a/src/corelib/kernel/qcore_mac_objc.mm
+++ b/src/corelib/kernel/qcore_mac_objc.mm
@@ -93,6 +93,45 @@ QMacAutoReleasePool::~QMacAutoReleasePool()
[static_cast<NSAutoreleasePool*>(pool) drain];
}
+#ifdef Q_OS_MACOS
+/*!
+ Ensure that Objective-C objects auto-released in main(), directly or indirectly,
+ after QCoreApplication construction, are released when the app goes out of scope.
+ The memory will be reclaimed by the system either way when the process exits,
+ but by having a root level pool we ensure that the objects get their dealloc
+ methods called, which is useful for debugging object ownership graphs, etc.
+*/
+
+QT_END_NAMESPACE
+#define ROOT_LEVEL_POOL_MARKER QT_ROOT_LEVEL_POOL__THESE_OBJECTS_WILL_BE_RELEASED_WHEN_QAPP_GOES_OUT_OF_SCOPE
+@interface QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) : NSObject @end
+@implementation QT_MANGLE_NAMESPACE(ROOT_LEVEL_POOL_MARKER) @end
+QT_NAMESPACE_ALIAS_OBJC_CLASS(ROOT_LEVEL_POOL_MARKER);
+QT_BEGIN_NAMESPACE
+
+const char ROOT_LEVEL_POOL_DISABLE_SWITCH[] = "QT_DISABLE_ROOT_LEVEL_AUTORELEASE_POOL";
+
+QMacRootLevelAutoReleasePool::QMacRootLevelAutoReleasePool()
+{
+ if (qEnvironmentVariableIsSet(ROOT_LEVEL_POOL_DISABLE_SWITCH))
+ return;
+
+ pool.reset(new QMacAutoReleasePool);
+
+ [[[ROOT_LEVEL_POOL_MARKER alloc] init] autorelease];
+
+ if (qstrcmp(qgetenv("OBJC_DEBUG_MISSING_POOLS"), "YES") == 0) {
+ qDebug("QCoreApplication root level NSAutoreleasePool in place. Break on ~%s and use\n" \
+ "'p [NSAutoreleasePool showPools]' to show leaked objects, or set %s",
+ __FUNCTION__, ROOT_LEVEL_POOL_DISABLE_SWITCH);
+ }
+}
+
+QMacRootLevelAutoReleasePool::~QMacRootLevelAutoReleasePool()
+{
+}
+#endif
+
// -------------------------------------------------------------------------
#ifdef Q_OS_OSX
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index c2c5a519aa..12e9518979 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -68,6 +68,7 @@
#endif
#include "qstring.h"
+#include "qscopedpointer.h"
#if defined( __OBJC__) && defined(QT_NAMESPACE)
#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
@@ -96,6 +97,18 @@ protected:
T value;
};
+
+#ifdef Q_OS_MACOS
+class QMacRootLevelAutoReleasePool
+{
+public:
+ QMacRootLevelAutoReleasePool();
+ ~QMacRootLevelAutoReleasePool();
+private:
+ QScopedPointer<QMacAutoReleasePool> pool;
+};
+#endif
+
/*
Helper class that automates refernce counting for CFtypes.
After constructing the QCFType object, it can be copied like a
diff --git a/src/corelib/kernel/qcoreapplication_p.h b/src/corelib/kernel/qcoreapplication_p.h
index c646786296..da6ce1249f 100644
--- a/src/corelib/kernel/qcoreapplication_p.h
+++ b/src/corelib/kernel/qcoreapplication_p.h
@@ -58,6 +58,10 @@
#include "private/qobject_p.h"
#endif
+#ifdef Q_OS_MACOS
+#include "private/qcore_mac_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
typedef QList<QTranslator*> QTranslatorList;
@@ -85,6 +89,10 @@ public:
QString appName() const;
QString appVersion() const;
+#ifdef Q_OS_MACOS
+ QMacRootLevelAutoReleasePool autoReleasePool;
+#endif
+
#ifdef Q_OS_DARWIN
static QString infoDictionaryStringProperty(const QString &propertyName);
#endif