From aa5d730eab80b0d105564fd96d7b2257b44007a8 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 16 Jun 2016 18:18:43 -0700 Subject: [PATCH] Deallocate objects on a serial queue specific for deallocation (#1737) [Performance] Prevent GCD thread explosion due to object deallocation workloads (serial deallocation queue). --- AsyncDisplayKit/ASMultiplexImageNode.mm | 2 +- AsyncDisplayKit/ASNetworkImageNode.mm | 2 +- AsyncDisplayKit/ASTextNode.mm | 2 +- AsyncDisplayKit/Private/ASInternalHelpers.h | 9 ++++++++- AsyncDisplayKit/Private/ASInternalHelpers.mm | 11 +++++++++++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/ASMultiplexImageNode.mm b/AsyncDisplayKit/ASMultiplexImageNode.mm index a1c6660fd6..19145359ba 100644 --- a/AsyncDisplayKit/ASMultiplexImageNode.mm +++ b/AsyncDisplayKit/ASMultiplexImageNode.mm @@ -531,7 +531,7 @@ - (void)_clearImage BOOL shouldReleaseImageOnBackgroundThread = imageSize.width > kMinReleaseImageOnBackgroundSize.width || imageSize.height > kMinReleaseImageOnBackgroundSize.height; if (shouldReleaseImageOnBackgroundThread) { - ASPerformBlockOnBackgroundThread(^{ + ASPerformBlockOnDeallocationQueue(^{ image = nil; }); } diff --git a/AsyncDisplayKit/ASNetworkImageNode.mm b/AsyncDisplayKit/ASNetworkImageNode.mm index 3ce5e4b12f..279f1bca79 100755 --- a/AsyncDisplayKit/ASNetworkImageNode.mm +++ b/AsyncDisplayKit/ASNetworkImageNode.mm @@ -378,7 +378,7 @@ - (void)_clearImage BOOL shouldReleaseImageOnBackgroundThread = imageSize.width > kMinReleaseImageOnBackgroundSize.width || imageSize.height > kMinReleaseImageOnBackgroundSize.height; if (shouldReleaseImageOnBackgroundThread) { - ASPerformBlockOnBackgroundThread(^{ + ASPerformBlockOnDeallocationQueue(^{ image = nil; }); } diff --git a/AsyncDisplayKit/ASTextNode.mm b/AsyncDisplayKit/ASTextNode.mm index 5fc9ac2919..fedcfaa091 100644 --- a/AsyncDisplayKit/ASTextNode.mm +++ b/AsyncDisplayKit/ASTextNode.mm @@ -260,7 +260,7 @@ - (void)_invalidateRenderer // actually dealloc. __block ASTextKitRenderer *renderer = _renderer; - ASPerformBlockOnBackgroundThread(^{ + ASPerformBlockOnDeallocationQueue(^{ renderer = nil; }); _renderer = nil; diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.h b/AsyncDisplayKit/Private/ASInternalHelpers.h index 8f154949a6..cff8c1fc53 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.h +++ b/AsyncDisplayKit/Private/ASInternalHelpers.h @@ -17,8 +17,15 @@ ASDISPLAYNODE_EXTERN_C_BEGIN BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector); BOOL ASSubclassOverridesClassSelector(Class superclass, Class subclass, SEL selector); + +/// Dispatches the given block to the main queue if not already running on the main thread void ASPerformBlockOnMainThread(void (^block)()); -void ASPerformBlockOnBackgroundThread(void (^block)()); // DISPATCH_QUEUE_PRIORITY_DEFAULT + +/// Dispatches the given block to a background queue with priority of DISPATCH_QUEUE_PRIORITY_DEFAULT if not already run on a background queue +void ASPerformBlockOnBackgroundThread(void (^block)()); // DISPATCH_QUEUE_PRIORITY_DEFAULT + +/// Dispatches a block on to a serial queue that's main purpose is for deallocation of objects on a background thread +void ASPerformBlockOnDeallocationQueue(void (^block)()); CGFloat ASScreenScale(); diff --git a/AsyncDisplayKit/Private/ASInternalHelpers.mm b/AsyncDisplayKit/Private/ASInternalHelpers.mm index e18b932ce9..4d4ccbbf74 100644 --- a/AsyncDisplayKit/Private/ASInternalHelpers.mm +++ b/AsyncDisplayKit/Private/ASInternalHelpers.mm @@ -52,6 +52,17 @@ void ASPerformBlockOnBackgroundThread(void (^block)()) } } +void ASPerformBlockOnDeallocationQueue(void (^block)()) +{ + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("org.AsyncDisplayKit.deallocationQueue", DISPATCH_QUEUE_SERIAL); + }); + + dispatch_async(queue, block); +} + CGFloat ASScreenScale() { static CGFloat __scale = 0.0;