我花了一些时间来理解我的代码中的一些大内存泄漏,因此在简化代码之后,剩下的是:
@interface TestLayer: CALayer
@end
@implementation TestLayer
-(void)dealloc
{
NSLog(@"dealloc called");
}
@end
@implementation AppDelegate
#define ENABLE_LEAK 1
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
for (int i=0; i<10; i++) {
@autoreleasepool {
TestLayer* test = [TestLayer layer];
#if ENABLE_LEAK
CALayer* l = [CALayer layer];
[test addSublayer:l];
[l removeFromSuperlayer];
l = nil;
#endif
test = nil;
}
}
return YES;
}
.....
如果ENABLE_LEAK设置为0,则正确调用TestLayer中的dealloc 10次。 但是,如果将其设置为1,则在此之前不会调用TestLayer中的dealloc,它会返回应用程序didFinishLaunchingWithOptions:。 实际上只是调用[test setNeedsLayout];没有添加任何子层会导致TestLayer泄漏。
我正在使用类似的代码来生成一些脱机内容,并且不会用于仅使用预生成的脱机内容的最终应用程序。
有人知道我的TestLayer是什么,如何说服它释放它?
答案 0 :(得分:2)
正如 Cristi 在其中一项评论中所建议的那样,仅使用CALayer
就解决了我所有与内存泄漏和CATransaction.flush()
有关的问题>
它就像一个魅力?
答案 1 :(得分:1)
在doc for CATransaction中,如果您修改层而不显式打开一个层,则将创建一个隐式事务。该事务在下一次运行循环迭代时自动刷新。由于要在单个主线程方法调用中进行迭代,因此运行循环不会关闭。如您所说,在您返回后,将调用deallocs DO。假定事务将所有操作(添加和删除)存储在某种形式的堆栈中,并保留它们,并且仅在事务结束时才进行处理。因此,您所看到的行为是预期的,如果您确实需要在单个运行循环迭代中清理引用,则可能需要自己明确地处理事务,而不是冲刷隐式事务,这可能导致性能低下或意外的副作用。 / p>
答案 2 :(得分:0)
让我猜测-您在项目中不使用ARC吗?
我尝试了几种方法来重现您对上述泄漏的主张,但找不到任何办法使之发生。
我在您的班级添加了标签:
@interface TestLayer: CALayer
@property (nonatomic, assign) int tag;
@end
@implementation TestLayer
-(void)dealloc
{
NSLog(@"dealloc called for %d", self.tag);
}
@end
首先,我在完全相同的地方尝试了您的代码AppDelegate:
for (int i=0; i<10; i++) {
@autoreleasepool {
TestLayer* test = [TestLayer layer];
test.tag = 100;
CALayer* l = [CALayer layer];
[test addSublayer:l];
[l removeFromSuperlayer];
l = nil;
test = nil;
}
}
它每次都会打印dealloc
!
然后,在我的第一个视图控制器中,我对其进行了少许修改:
- (void)viewDidLoad {
[super viewDidLoad];
tl = [TestLayer layer]; // its an ivar
tl.tag = 100;
for (int i=0; i<10; i++) {
@autoreleasepool {
TestLayer *l = [TestLayer layer];
l.tag = i + 10;
[tl addSublayer:l];
[tl removeFromSuperlayer]; // tried this, also tried commenting it out
}
}
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
NSArray *sl = [self->tl.sublayers copy];
for (TestLayer *l in sl) {
[l removeFromSuperlayer];
}
self->tl = nil;
});
}
我唯一可以得出的结论是您没有使用ARC,应该提一下。
PS:如果不使用ARC,我只能假设CALayer layer
返回的保留计数为1的对象,并且该对象未自动释放。如果是这样,则需要显式发送一条release
消息。