_01_《高性能iOS应用开发》——内存管理

  • 应用中新创建的每个线程都有专用的栈空间,线程的最大栈空间很小,如果层级太深,可能造成栈溢出。
  • 每个进程的所有线程共享同一个堆。
  • 在相册类 APP 中,如果所有的图片都在 dataSource 中,这个数组将会很大,从而导致很高的峰值内存使用。可以固定数组的大小,在用户滚动视图时换入或者换出图片。
  • A方法创建了一个对象并返回了a,B方法调用A方法,B内引用a,那么不应该在 B 中释放 a,因为 B 方法中没有创建实体对象,不要在 B 中使用 release. 当创建一个对象并将其从非 alloc 方法返回时,应使用 autorelease。这样可以保证对象被释放。

- (NSString *)address {
    NSString *ad = [[[NSString alloc] initWithString:@"贝克街 221B"] autorelease];
    return ad;
}
...
- (void)showPersonAddress:(Person *)p {
    NSString *address = [p address];
    NSLog(@"Person's Address: %@", address);
}

  • 自己创建 autoreleasepool 块的情况:

    1. 当有一个创建了很多临时对象的循环时,在循环中使用 autoreleasepool 可以为每一次循环释放内存。循环次数多时,对内存的需求大大降低。
    2. 自己创建的线程也应创建一个自己的 autoreleasepool.
  • __weak: 当没有强引用指向对象时,弱引用会被置为 nil.

  • __unsafe__unretained: 当没有强引用指向对象时,弱引用不会被置为 nil.

  • 循环引用
    双向链表和环形链表中也存在循环引用。此时,一旦明确对象不会再被使用,需要编写代码打破链表的链接。

  • 线程与计时器

- (void)startCountdown {
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateFeed:) userInfo:nil repeats:YES];
}

- (void)dealloc {
    [self.timer invalidate];
}

很明显上面的例子中产生了循环引用,直到 [self.timer invalidate] 执行,timer 才会取消对 self 的强引用,但是由于建立了循环引用,这里的 dealloc 并不会调用,timer 并不会执行 invalidate。所以需要自定义一个清理的方法执行清理操作。这样的清理方法可以在离开当前页面点击返回时调用。
另一种清理方案是将持有关系分散到多个类中——任务类执行具体动作,所有者类调用任务。类似于将 taget 设置为任务类的代理。

  • 观察者
    键值观察和通知中心不会维持观察对象、被观察对象以及上下文对象的强引用。如果要持续对一个对象进行观察,需要自行维护对它的强引用。

  • 避免大量使用单例和全局状态对象。

你可能感兴趣的:(_01_《高性能iOS应用开发》——内存管理)