mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-04 20:00:53 +00:00
Create a new dealloc queue that is more efficient (#931)
* Fork dealloc queue in an experiment * Fix and put back * Use the right selector * Go simpler * Clarify name * Type inference * Use CFTypeRefs like a boss * Improve comments * License header
This commit is contained in:
parent
b2e5f9ec64
commit
8b890f07be
@ -54,6 +54,7 @@
|
|||||||
- [ASCollectionNode/ASTableNode] Fix a crash occurs while remeasuring cell nodes. [Huy Nguyen](https://github.com/nguyenhuy) [#917](https://github.com/TextureGroup/Texture/pull/917)
|
- [ASCollectionNode/ASTableNode] Fix a crash occurs while remeasuring cell nodes. [Huy Nguyen](https://github.com/nguyenhuy) [#917](https://github.com/TextureGroup/Texture/pull/917)
|
||||||
- Fix an issue where ASConfigurationDelegate would not call out for "control" users. If set, it now receives events whenever an experimental feature decision point occurs, whether it's enabled or not. [Adlai Holler](https://github.com/Adlai-Holler)
|
- Fix an issue where ASConfigurationDelegate would not call out for "control" users. If set, it now receives events whenever an experimental feature decision point occurs, whether it's enabled or not. [Adlai Holler](https://github.com/Adlai-Holler)
|
||||||
- [ASDisplayNode] Fix an issue that causes a node to sometimes return an outdated calculated size or size range. [Huy Nguyen](https://github.com/nguyenhuy) [#808](https://github.com/TextureGroup/Texture/pull/808)
|
- [ASDisplayNode] Fix an issue that causes a node to sometimes return an outdated calculated size or size range. [Huy Nguyen](https://github.com/nguyenhuy) [#808](https://github.com/TextureGroup/Texture/pull/808)
|
||||||
|
- Add an experimental deallocation queue implementation that's more efficient. [Adlai Holler](https://github.com/Adlai-Holler)
|
||||||
|
|
||||||
## 2.6
|
## 2.6
|
||||||
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
|
- [Xcode 9] Updated to require Xcode 9 (to fix warnings) [Garrett Moon](https://github.com/garrettmoon)
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
"exp_interface_state_coalesce",
|
"exp_interface_state_coalesce",
|
||||||
"exp_unfair_lock",
|
"exp_unfair_lock",
|
||||||
"exp_infer_layer_defaults",
|
"exp_infer_layer_defaults",
|
||||||
"exp_network_image_queue"
|
"exp_network_image_queue",
|
||||||
|
"exp_dealloc_queue_v2"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ typedef NS_OPTIONS(NSUInteger, ASExperimentalFeatures) {
|
|||||||
ASExperimentalUnfairLock = 1 << 3, // exp_unfair_lock
|
ASExperimentalUnfairLock = 1 << 3, // exp_unfair_lock
|
||||||
ASExperimentalLayerDefaults = 1 << 4, // exp_infer_layer_defaults
|
ASExperimentalLayerDefaults = 1 << 4, // exp_infer_layer_defaults
|
||||||
ASExperimentalNetworkImageQueue = 1 << 5, // exp_network_image_queue
|
ASExperimentalNetworkImageQueue = 1 << 5, // exp_network_image_queue
|
||||||
|
ASExperimentalDeallocQueue = 1 << 6, // exp_dealloc_queue_v2
|
||||||
ASExperimentalFeatureAll = 0xFFFFFFFF
|
ASExperimentalFeatureAll = 0xFFFFFFFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,7 +19,8 @@ NSArray<NSString *> *ASExperimentalFeaturesGetNames(ASExperimentalFeatures flags
|
|||||||
@"exp_interface_state_coalesce",
|
@"exp_interface_state_coalesce",
|
||||||
@"exp_unfair_lock",
|
@"exp_unfair_lock",
|
||||||
@"exp_infer_layer_defaults",
|
@"exp_infer_layer_defaults",
|
||||||
@"exp_network_image_queue"]));
|
@"exp_network_image_queue",
|
||||||
|
@"exp_dealloc_queue_v2"]));
|
||||||
|
|
||||||
if (flags == ASExperimentalFeatureAll) {
|
if (flags == ASExperimentalFeatureAll) {
|
||||||
return allNames;
|
return allNames;
|
||||||
|
@ -76,14 +76,12 @@ AS_SUBCLASSING_RESTRICTED
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
AS_SUBCLASSING_RESTRICTED
|
|
||||||
@interface ASDeallocQueue : NSObject
|
@interface ASDeallocQueue : NSObject
|
||||||
|
|
||||||
@property (class, atomic, readonly) ASDeallocQueue *sharedDeallocationQueue;
|
@property (class, atomic, readonly) ASDeallocQueue *sharedDeallocationQueue;
|
||||||
+ (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED;
|
+ (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED;
|
||||||
|
|
||||||
- (void)test_drain;
|
- (void)drain;
|
||||||
|
|
||||||
- (void)releaseObjectInBackground:(id __strong _Nullable * _Nonnull)objectPtr;
|
- (void)releaseObjectInBackground:(id __strong _Nullable * _Nonnull)objectPtr;
|
||||||
|
|
||||||
|
@ -39,23 +39,41 @@ static void runLoopSourceCallback(void *info) {
|
|||||||
|
|
||||||
#pragma mark - ASDeallocQueue
|
#pragma mark - ASDeallocQueue
|
||||||
|
|
||||||
@implementation ASDeallocQueue {
|
@interface ASDeallocQueueV1 : ASDeallocQueue
|
||||||
NSThread *_thread;
|
@end
|
||||||
NSCondition *_condition;
|
@interface ASDeallocQueueV2 : ASDeallocQueue
|
||||||
std::deque<id> _queue;
|
@end
|
||||||
ASDN::RecursiveMutex _queueLock;
|
|
||||||
}
|
@implementation ASDeallocQueue
|
||||||
|
|
||||||
+ (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED
|
+ (ASDeallocQueue *)sharedDeallocationQueue NS_RETURNS_RETAINED
|
||||||
{
|
{
|
||||||
static ASDeallocQueue *deallocQueue = nil;
|
static ASDeallocQueue *deallocQueue = nil;
|
||||||
static dispatch_once_t onceToken;
|
static dispatch_once_t onceToken;
|
||||||
dispatch_once(&onceToken, ^{
|
dispatch_once(&onceToken, ^{
|
||||||
deallocQueue = [[ASDeallocQueue alloc] init];
|
if (ASActivateExperimentalFeature(ASExperimentalDeallocQueue)) {
|
||||||
|
deallocQueue = [[ASDeallocQueueV2 alloc] init];
|
||||||
|
} else {
|
||||||
|
deallocQueue = [[ASDeallocQueueV1 alloc] init];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return deallocQueue;
|
return deallocQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)releaseObjectInBackground:(id _Nullable __strong *)objectPtr
|
||||||
|
{
|
||||||
|
ASDisplayNodeFailAssert(@"Abstract method.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation ASDeallocQueueV1 {
|
||||||
|
NSThread *_thread;
|
||||||
|
NSCondition *_condition;
|
||||||
|
std::deque<id> _queue;
|
||||||
|
ASDN::RecursiveMutex _queueLock;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)releaseObjectInBackground:(id _Nullable __strong *)objectPtr
|
- (void)releaseObjectInBackground:(id _Nullable __strong *)objectPtr
|
||||||
{
|
{
|
||||||
if (objectPtr != NULL && *objectPtr != nil) {
|
if (objectPtr != NULL && *objectPtr != nil) {
|
||||||
@ -147,12 +165,12 @@ static void runLoopSourceCallback(void *info) {
|
|||||||
_thread = nil;
|
_thread = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)test_drain
|
- (void)drain
|
||||||
{
|
{
|
||||||
[self performSelector:@selector(_test_drain) onThread:_thread withObject:nil waitUntilDone:YES];
|
[self performSelector:@selector(_drain) onThread:_thread withObject:nil waitUntilDone:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_test_drain
|
- (void)_drain
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
@ -182,6 +200,57 @@ static void runLoopSourceCallback(void *info) {
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation ASDeallocQueueV2 {
|
||||||
|
std::vector<CFTypeRef> _queue;
|
||||||
|
ASDN::Mutex _lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
ASDisplayNodeFailAssert(@"Singleton should not dealloc.");
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)releaseObjectInBackground:(id _Nullable __strong *)objectPtr
|
||||||
|
{
|
||||||
|
NSParameterAssert(objectPtr != NULL);
|
||||||
|
|
||||||
|
// Cast to CFType so we can manipulate retain count manually.
|
||||||
|
auto cfPtr = (CFTypeRef *)(void *)objectPtr;
|
||||||
|
if (!cfPtr || !*cfPtr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock.lock();
|
||||||
|
auto isFirstEntry = _queue.empty();
|
||||||
|
// Push the pointer into our queue and clear their pointer.
|
||||||
|
// This "steals" the +1 from ARC and nils their pointer so they can't
|
||||||
|
// access or release the object.
|
||||||
|
_queue.push_back(*cfPtr);
|
||||||
|
*cfPtr = NULL;
|
||||||
|
_lock.unlock();
|
||||||
|
|
||||||
|
if (isFirstEntry) {
|
||||||
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.100 * NSEC_PER_SEC)), dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
|
||||||
|
[self drain];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)drain
|
||||||
|
{
|
||||||
|
@autoreleasepool {
|
||||||
|
_lock.lock();
|
||||||
|
auto q = std::move(_queue);
|
||||||
|
_lock.unlock();
|
||||||
|
for (auto ref : q) {
|
||||||
|
// NOTE: Could check that retain count is 1 and retry later if not.
|
||||||
|
CFRelease(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
#if AS_KDEBUG_ENABLE
|
#if AS_KDEBUG_ENABLE
|
||||||
/**
|
/**
|
||||||
* This is real, private CA API. Valid as of iOS 10.
|
* This is real, private CA API. Valid as of iOS 10.
|
||||||
|
@ -95,7 +95,7 @@ static __weak ASTestCase *currentTestCase;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now that the autorelease pool is drained, drain the dealloc queue also.
|
// Now that the autorelease pool is drained, drain the dealloc queue also.
|
||||||
[[ASDeallocQueue sharedDeallocationQueue] test_drain];
|
[[ASDeallocQueue sharedDeallocationQueue] drain];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (ASTestCase *)currentTestCase
|
+ (ASTestCase *)currentTestCase
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
//
|
//
|
||||||
// AppDelegate.m
|
// AppDelegate.m
|
||||||
// Sample
|
// Texture
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
// Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
|
||||||
// This source code is licensed under the BSD-style license found in the
|
// This source code is licensed under the BSD-style license found in the
|
||||||
// LICENSE file in the root directory of this source tree. An additional grant
|
// LICENSE file in the /ASDK-Licenses directory of this source tree. An additional
|
||||||
// of patent rights can be found in the PATENTS file in the same directory.
|
// grant of patent rights can be found in the PATENTS file in the same directory.
|
||||||
//
|
//
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// Modifications to this file made after 4/13/2017 are: Copyright (c) through the present,
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// Pinterest, Inc. Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
// you may not use this file except in compliance with the License.
|
||||||
// FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
// You may obtain a copy of the License at
|
||||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
//
|
||||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
@ -55,3 +55,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@implementation ASConfiguration (UserProvided)
|
||||||
|
|
||||||
|
+ (ASConfiguration *)textureConfiguration
|
||||||
|
{
|
||||||
|
ASConfiguration *cfg = [[ASConfiguration alloc] init];
|
||||||
|
cfg.experimentalFeatures = ASExperimentalDeallocQueue;
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user