内存管理
- 操作对象的生命周期
- 自动释放池:在
NSOperation
的main
方法中,如果有大量临时对象创建,可以手动创建自动释放池。例如:
- (void)main {
@autoreleasepool {
// 大量临时对象的操作
for (int i = 0; i < 1000; i++) {
NSString *tempString = [NSString stringWithFormat:@"%d", i];
// 对tempString进行操作
}
}
}
- 强引用与弱引用:当
NSOperation
对象被添加到NSOperationQueue
时,NSOperationQueue
会对其持有强引用。若在外部也持有对该NSOperation
对象的强引用,可能导致循环引用。可以通过在外部使用弱引用来避免,比如:
__weak MyOperation *weakOperation = [[MyOperation alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:weakOperation];
- 避免内存泄漏
- 完成块的使用:如果
NSOperation
使用了完成块,要注意在完成块中避免对self
的强引用,防止循环引用。可以使用__weak
修饰符,例如:
__weak typeof(self) weakSelf = self;
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 这里使用weakSelf
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
// 对strongSelf进行操作
}
}];
- 操作完成时的清理:在
NSOperation
的finish
方法(自定义NSOperation
时重写该方法)或者完成块中,释放操作过程中创建的资源,比如关闭文件句柄、释放数据库连接等。
性能优化策略
- 合理设置队列的最大并发数
- 根据任务类型:如果任务是CPU密集型的,如复杂的计算任务,最大并发数应设置得较小,一般为CPU核心数,以避免过多线程竞争CPU资源导致性能下降。例如,在iOS设备上,通常可以根据
[NSProcessInfo processInfo].activeProcessorCount
来设置最大并发数。
NSOperationQueue *cpuIntensiveQueue = [[NSOperationQueue alloc] init];
cpuIntensiveQueue.maxConcurrentOperationCount = [NSProcessInfo processInfo].activeProcessorCount;
- 如果任务是I/O密集型:如网络请求或文件读写,可以适当提高最大并发数,因为I/O操作等待时间长,更多线程可以在等待I/O完成时利用CPU资源。但也不能设置过大,否则过多的线程切换会带来额外开销。可以通过测试不同的值,根据实际性能表现来确定,比如设置为8 - 16等。
- 处理队列中任务的动态添加与移除对性能的影响
- 批量操作:尽量避免频繁单个任务的添加与移除。如果需要添加多个任务,最好批量添加,例如:
NSMutableArray<NSOperation *> *operations = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
// 任务操作
}];
[operations addObject:operation];
}
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperations:operations waitUntilFinished:NO];
- 移除操作的时机:在移除任务时,要考虑任务的执行状态。如果任务已经开始执行,直接移除可能导致未完成的工作和资源泄漏。可以设置一个标记,在任务下次检查状态时,根据标记决定是否停止执行并清理资源,然后再从队列中移除。例如:
@interface MyOperation : NSOperation
@property (nonatomic, assign) BOOL shouldCancel;
@end
@implementation MyOperation
- (void)main {
while (!self.isCancelled &&!self.shouldCancel) {
// 任务执行代码
}
// 清理资源
}
@end
// 在外部移除任务时
MyOperation *operation = [queue.operations firstObject];
operation.shouldCancel = YES;
[queue removeOperation:operation];