
上篇文章讲述了iOS内存管理的基本概念,这里是一些内存优化的小技巧 Strong Weak Dance这个大家都知道,就是处理循环引用,合理使用weak 和unowned 。 降低内存峰值Lazy Allocation延时加载是很常用的一种优化方法,如果有些情况我们不会立即使用某一对象和某些资源,我们完全可以在使用的时候再进行加载,这些就可以避免初次运行程序的时候内存消耗严重。 lazy var goodsImageView: UIImageView = {
let goodsImageView = UIImageView()
return goodsImageView
}()
在喵神的博客中,也发现了很好玩的地方,Swift 标准库中,定义了一些Lazy 方法,可以配合像 map 或是 filter 这类接受闭包并进行运行的方法一起,让整个行为变成延时进行。 let data = 1...3
let result = data.lazy.map {
(i: Int) -> Int in
print('正在处理 \(i)')
return i * 2
}
print('准备访问结果')
for i in result {
print('操作后结果为 \(i)')
}
print('操作完毕')
运行结果为: // 准备访问结果
// 正在处理 1
// 操作后结果为 2
// 正在处理 2
// 操作后结果为 4
// 正在处理 3
// 操作后结果为 6
// 操作完毕
图片的读取相信写代码的时候都会涉及到图片的读取,我们经常使用的方法 imageView?.image = UIImage(named: name)
imageView?.image = UIImage(contentsOfFile: path)
NSData & 内存映射文件在我们经常使用NSData 时,出镜率很高的两个方法 public init?(contentsOfFile path: String)
public init(contentsOfFile path: String, options readOptionsMask: NSDataReadingOptions) throws
第二种比第一个多一个Options ,第二种方式是创建了一个内存映射文件,把内容放在虚拟内存中,只有读取操作的时候才会读到相对应页的物理内存页中。所以后者,对于大文件是很划算的,推荐使用第二种。对于可选的方式如下: 
其他方式在庄延军老师的分享中,还有其他一些技巧,但是对于只懂Swift的我,实在没接触过哪些方案,等我接触之后,再来写第三个分享。下面简单列举一下: calloc VS malloc memset
栈内存分配
NSAutoReleasePool从MRC 时代说起,当需要我们手动来管理对象引用计数的时候,我们需要Retain 和Release 方法,那么可能一个线程中有大量的Retain 和Release 方法,这个时候使用一个池一起管理他们是不是方便很多,将线程中要执行的任务都放在自动释放池中,自动释放池会捕获所有任务中的对象,在任务结束或线程关闭之时自动释放这些对象。 当然自动释放池都会使用NSAutoreleasePool 类创建,并在自动释放池收到 drain 消息时将这些对象的引用计数减一,然后将它们从池子中移除 (这一过程形象地称为“抽干池子”)。 在ARC 时代,不再使用NSAutoreleasePool 来创建自动释放池,而是使用@autoreleasepool 代码块,新建Objective-C 工程的时候,会帮我们创建一个main.m 文件,已经帮我们在主线程创建了一个自动释放池。 int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
} 更进一步,其实@autoreleasepool 在编译时会被展开为 NSAutoreleasePool ,并且在每个主Runloop 结束时进行drain 操作。 那么到了Swift时代,又具有了新的变化,不需要手动地调用autorelease 这样的方法来管理引用计数,但是这些方法还是都会被调用的,只不过是编译器在编译时在合适的地方帮我们加入了而已。 在Swift标准库中可以发现: public func autoreleasepool(@noescape code: () -> ())
那么我们就可以利用闭包的特点,在需要的时候非常简便的使用它 autoreleasepool {
// 线程执行任务的逻辑代码
}
AutoReleasePool为什么在ARC 时代还需要使用自动释放池呢?其原因就是为了避免内存峰值,那比如说我有一个很大的For 循环,里面不断读入较大的文件。其实每迭代一次,资源都已经用完了(就是说我用好了,还你),不需要再用了,这个时候就可以释放了,但是程序需要等到Runloop 结束的时候才可以释放,这就增大了内存的峰值。 上面的话有点绕,但是真心非常重要。 那么怎么做,可以减小内存峰值呢?我们可以在For 循环中添加autoreleasepool ,这样就可以保证每次迭代完毕一次就可以释放点内存。 func loadBigData() {
for i in 1...10000 {
autoreleasepool {
let data = NSData.dataWithContentsOfFile(
path, options: nil, error: nil)
}
}
}
简单总结上面的阐述了多种方法,其中对于降低内存峰值有作用的是: Lazy Allocation
图片的读取的正确方式 NSData & 内存映射文件
calloc VS malloc memset
栈内存分配 autoReleasePool
内存警告处理到收到内存警告的时候,所要做的:
|