测试已测试 | ✓ |
语言语言 | Objective C++Objective C++ |
许可证 | BSD |
发布最后发布 | 2017年11月 |
由 Dave Lee,Grzegorz Pstrucha,Jeremie Marguerie 维护。
一个iOS库,使用运行时分析来查找保留循环。
保留循环是创建内存泄漏最常见的方式之一。创建保留循环非常容易,而且往往很难发现。
FBRetainCycleDetector 的目标是帮助在运行时找到保留循环。
此项目的功能受到了 Circle 的影响。
将以下内容添加到 Cartfile 中
github "facebook/FBRetainCycleDetector"
FBRetainCycleDetector
是从非调试构建中构建的,因此当您想要测试它时,请使用
carthage update --configuration Debug
将以下内容添加到 podspec 中
pod 'FBRetainCycleDetector'
您只能在 Debug
构建中完全使用 FBRetainCycleDetector
。这是由 编译标志 控制的,可以提供给构建以便在其他配置中使用。
让我们快速进入
#import <FBRetainCycleDetector/FBRetainCycleDetector.h>
FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
[detector addCandidate:myObject];
NSSet *retainCycles = [detector findRetainCycles];
NSLog(@"%@", retainCycles);
- (NSSet
将返回一组包含封装对象的数组。这最初可能很难看,但让我们来看看。此集合中的每个数组将表示一个保留循环。此数组中的每个元素都封装了此保留循环中的一个对象。检查 FBObjectiveCGraphElement。
示例输出可能如下所示
{(
(
"-> MyObject ",
"-> _someObject -> __NSArrayI "
)
)}
MyObject
通过 someObject
属性保留了它所构成的部分 NSArray
。
FBRetainCycleDetector 将寻找最长不超过 10 个对象的循环。
我们可以将其做得更大(虽然这将变得更慢!)。
FBRetainCycleDetector *detector = [FBRetainCycleDetector new];
[detector addCandidate:myObject];
NSSet *retainCycles = [detector findRetainCyclesWithMaxCycleLength:100];
还可能有我们想要排除的保留循环。这是因为并非每个保留循环都是泄漏,我们可能想要过滤掉它们。
为此,我们需要指定过滤器
NSMutableArray *filters = @[
FBFilterBlockWithObjectIvarRelation([UIView class], @"_subviewCache"),
];
// Configuration object can describe filters as well as some options
FBObjectGraphConfiguration *configuration =
[[FBObjectGraphConfiguration alloc] initWithFilterBlocks:filters
shouldInspectTimers:YES];
FBRetainCycleDetector *detector = [[FBRetainCycleDetector alloc] initWithConfiguration:configuration];
[detector addCandidate:myObject];
NSSet *retainCycles = [detector findRetainCycles];
每个过滤器都是具有两个 FBObjectiveCGraphElement
对象的块,它们可以声明其关系是否有效。
检查 FBStandardGraphEdgeFilters 了解如何使用过滤器。
NSTimer 可能很麻烦,因为它会保留其目标。这通常意味着保留循环。 FBRetainCycleDetector
可以检测这些,
但如果你想跳过它们,你可以在传递给 FBRetainCycleDetector
的配置中指定这一点。
FBObjectGraphConfiguration *configuration =
[[FBObjectGraphConfiguration alloc] initWithFilterBlocks:someFilters
shouldInspectTimers:NO];
FBRetainCycleDetector *detector = [[FBRetainCycleDetector alloc] initWithConfiguration:configuration];
Objective-C 允许我们使用 objc_setAssociatedObject 为每个对象设置关联对象。
这些关联对象在使用保留策略,如 OBJC_ASSOCIATION_RETAIN_NONATOMIC
时,可能会导致保留循环。FBRetainCycleDetector 可捕获这类循环,但要做到这一点,我们需要对其进行配置。在应用程序生命周期早期,最好是在 main.m
中,我们可以添加以下内容:
#import <FBRetainCycleDetector/FBAssociationManager.h>
int main(int argc, char * argv[]) {
@autoreleasepool {
[FBAssociationManager hook];
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
在上面的代码中,[FBAssociationManager hook]
会使用 fishhook 来间接函数 objc_setAssociatedObject
和 objc_resetAssociatedObjects
,以追踪在创建之前的关联。
如果您想对应用程序进行性能分析,可能需要一个抽象的方式,以便获取 FBRetainCycleDetector
的候选对象。虽然您可以直接跟踪它,但您也可以使用 FBAllocationTracker。这是我们创建的一个小工具,可以帮助您跟踪对象。它提供简单的 API,您可以查询例如所有给定类的实例,或当前跟踪的所有类名等。
FBAllocationTracker
和 FBRetainCycleDetector
可以很好地协同工作。我们已经创建了一个小示例和drop-in项目,名为 FBMemoryProfiler,该项目利用了这两个项目。它提供了一个非常基础的 UI,您可以使用它来跟踪所有分配并从 UI 中强制执行保留循环检测。
请参阅 CONTRIBUTING 文件,以了解如何有所帮助。
FBRetainCycleDetector
是 BSD 许可的。我们还提供了一个额外的 专利许可。