1.简介
何为内存泄漏?
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。
在OC中的ARC环境下,两个或多个对象相互强引用造成引用环,内存不能释放,导致内存泄漏。
2.OC中内存泄漏的几种情况和解决办法
2.1对象间的循环引用
2.1.1普通对象的循环引用
解决方法是将对象之间引用环的某一强引用(strong)改为弱引用(weak)。
// ClassA
@property (nonatomic, weak) ClassA * a;
// ClassB
@property (nonatomic, strong) ClassB * b;
2.1.2block循环引用
对象持有block,而block中有直接或简介的访问了该对象,造成循环引用;解决方法在block内,用该对象的弱引用。
typedef int (^MySomeBlock) (int);
__weak typeof(self) weakself = self;
self.block = ^int(NSInteger i) {
weakself.window;
return i;
};
2.1.3delegate循环引用问题
该情况在OC中广泛存在,是2.1.1的一种情况。
@property (nonatomic, weak, nullable) id <UITableViewDelegate> delegate;
2.2NSNotification的观察者忘记移除
在合适的时机将观察者进行移除,比如在viewWillDisappear或者dealloc中。观察者一种是不带block的,这类观察者iOS9.0后无需手动移除。另一种是block块的观察者,需要移除;如果不移除,由于观察者强持有block块,这样造成每个观察者都持有一个block。如果接收到通知,多个观察者都会调用该block,造成重复调用。所以,一定要合适的时机移除该类观察者。
[[NSNotificationCenter defaultCenter] removeObserver:self];
2.3NSTimer循环引用
NSTimer强持有对象,对象强持有NSTimer时会造成循环引用;解决方法是在适当的时候调用NSTimer的invalidate方法;不要在强引用环中对象的dealloc中调用,否则不会打破引用环。
@interface NextViewController ()
@property (nonatomic, strong) NSTimer * timer;
@property (nonatomic, assign) NSInteger number;
@end
@implementation NextViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
// self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerEvent) userInfo:nil repeats:YES];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
self.number++;
NSLog(@"%ld", (long)self.number);
}];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self dismissViewControllerAnimated:YES completion:nil];
[self.timer invalidate];
}
- (void)timerEvent {
NSLog(@"NextViewController-timer");
}
- (void)dealloc
{
NSLog(@"NextViewController-dealloc");
}
2.4非OC对象内存处理
其它的对于CoreFoundation框架下的某些对象或变量需要手动释放(如CGContextRelease);C语言代码中的malloc等分配的内存,需要手动free释放内存。
+ (UIImage *)imageFromColor:(UIColor *)color size:(CGSize)size {
CGRect rect = CGRectMake(0, 0, size.width, size.height);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
CGContextRelease(context);
return img;
}
2.5大次数循环内存暴涨问题
当循环次数较大,且循环体内局部变量占用内存较大时,会出现该问题;解决方法是将循环体代码放入缓存池中。
NSMutableArray * imageList = [NSMutableArray new];
for (NSInteger i = 0; i < 10000; i++) {
@autoreleasepool {
UIImage * image = [UIImage imageNamed:[NSString stringWithFormat:@"image_%ld", i]];
[imageList addObject:image];
NSLog(image);
}
}
2.6加载大图片或者多个图片
使用imageWithContentsOfFile替换imageNamed。
2.7 UIWebView
在App中使用h5界面,使用WKWebView替换UIWebView;UIWebView在iOS12以后已经废弃,还是用WKWebView吧。
网友评论