循环引用就是当self 拥有一个block的时候,在block 又调用self的方法。这个时候self强引用了block,而在block中使用self也会强引用self。这样就会产生循环引用,导致两个对象都得不到释放。
self.myBlock = ^{
[self doSomething];
};
解决的方法:掐断其中的一条强引用,使之变成弱引用,变成这样,就打破了循环引用:
__weak typeof (self) weakSelf = self;
还有一些系统的Block,这些Block中不用做特殊处理就可以直接使用self,因为这些系统的Block由系统strong引用,我们的代码没有强引用它
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Self.a %@", self.a);
});
在使用 NSTimer addtarget 时,为了防止 target 被释放而导致的程序异常,timer 会强引用 target,所以这也是一处内存泄露的隐患。解决方法是使用线程安全的MSWeakTimer,然后在dealloc中主动调用invalidate
- (void)dealloc {
[timer invalidate];
}
performSelector分静态调用和动态调用,以下这种调用 selector 的方法和直接调用 selector 基本等效,执行效果相同,不存在内存泄露
[object methodName];
[object performSelector:@selector(methodName)];
还有一种动态绑定方式,编译器不知道即将调用的 selector 是什么,不了解方法签名和返回值,甚至是否有返回值都不懂,所以编译器无法用 ARC 的内存管理规则来判断返回值是否应该释放。因此,ARC 采用了比较谨慎的做法,不添加释放操作,即在方法返回对象时就可能将其持有,从而可能导致内存泄露。在ARC下编译会告警:
warning: performSelector may cause a leak because its selector is unknow [-Warc-performSelector-leak]
-(void)method:(SEL)selector {
[object performSelector:selector];
}
解决方式是使用函数指针,显示的声明这个函数
IMP imp = [viewController methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(viewController, selector);
把delegate声明为strong属性导致了循环引用
@property (nonatomic, strong) SampleViewController *delegate;
解决方法很简单把strong改成weak就行
@property (nonatomic, weak) SampleViewController *delegate;
如果某个ViewController中有无限循环,也会导致即使ViewController对应的view关掉了,ViewController也不能被释放。这种问题常发生于animation处理。
CATransition *transition = [CATransition animation];
transition.duration = 0.5;
tansition.repeatCount = HUGE_VALL;
[self.view.layer addAnimation:transition forKey:"myAnimation"];
解决办法是,在ViewController关掉的时候,停止这个animation
-(void)viewWillDisappear:(BOOL)animated {
[self.view.layer removeAllAnimations];
}
ARC是自动检测OBJC对象的,非objc对象就无能为力了,比如C或C++等。
C语言使用 malloc 开辟,free释放。
C++使用new 开辟,delete释放。
但是在ARC下,不会添加非OBJC对象释放语句,如果没去释放,也会造成内存泄露。