大多数浏览器和
Developer App 均支持流媒体播放。
-
优化 App 中的存储
App 中的数据存储方式不仅影响磁盘占用空间,也会影响 app 的性能和设备的电池续航能力。了解优化数据序列化、处理图像和同步到磁盘的技巧。了解如何利用 SQLite 中的功能来提高性能和安全性。
资源
相关视频
WWDC21
WWDC19
-
下载
(在你的app中优化存储空间 更好的性能和效率)
嗨 我是Kai Kaahaaina 今天 我同Alejandro Lucena一起 我们会介绍如何为你的app优化 存储空间
就像CPU内存一样 存储是一个 有限资源
当一个app最佳使用存储空间时 我们能更好地保证更长时间 的电池寿命、更好的性能、
减少app的内存占用和 保持设备的良好健康状态
今天我们主要要讲的优化主题是 高效率的图片资源
同步至硬盘 序列化数据文件 Core Data和SQLite
首先 高效率的图片资源 当屏幕尺寸变得大一些了 图片资源的尺寸也相应地增大了
在我们的演讲中 我们创建了一个 简单的示例app来整理目录 和最爱的图片
不过 甚至是在预加载一些照片时 我们的app也增大了24.6 百万字节的内存大小
我们现在来了解优化 我们app的尺寸的两种方式
首先是HEIC HEIC有时也被称为HEIF 它更有效率且能够取代JPEG
相同画质下 HEIC的文件大小 比JPEG小了50% 当然 它意味着一个 更小的磁盘空间和更小的文件大小 从网络上上传或下载变得更容易了
它们也能被更快的加载和保持到硬盘
HEIC也提供了很多JPEG 没有的其他功能 比如存储包含了深度和视差信息 的辅助图片的能力
HEIC也支持阿尔法和无损压缩
HEIC甚至允许你在单独的容器中 存储多张图片
iOS从iOS 11起 支持HEIC MacOS从macOS High Sierra 开始支持HEIC 它在其他操作系统也同样可用
那么 回到我们的示例app 我们从使用JPEG资源开始 它在磁盘中占据24.6兆字节
用HEIC取代JPEG格式后 我们能缩减这个app的尺寸 到17.9兆字节 通过使用HEIC就减少了27% 的占有量
另一个减少我们app 内存占用的方式是使用资源目录 资源目录是管理你app的资源 的一个很好的方式 比如app图标 设备和你的
不同尺寸的图片资源 资源目录提供了一个非常容易的 存储方式 具有多级分辨率的图片 这让它非常简单就能 支持很多不同的设备
我们也能使用资源目录来为 随需应变的资源做标记 这样用户就不需要看见它们下载 直到他们需要使用它们时
通过使用资源目录 我们同时获取了存储和性能的优点
我们首先减少了磁盘的内存占有量 因为资源目录使用了单一的经过优化 的格式来存储我们所有的图片资源 而不是个别文件
App Store也使用了 你资源目录的元数据来帮助支持 你的iOS app的app分割
这样当一个用户从商店下载 你的app时 他们只会获取到他们自己设备所需 的资源 这减轻了下载量 也节省了用户下载app的时间 他们很快就能开始使用你的app
我们的性能也得到了提升 再一次 由于资源目录优化了 我们图片资源的保存格式 图片能被更快地加载了 在app启动时优化效果尤其明显
特别是Mac上的硬件驱动 我们看到了app启动时性能提升了 10%
资源目录也让基于GPU的压缩 的适配变得很简单 这个压缩默认是无损的 但也支持有损格式的压缩
所有的都能使用硬件加速的解压
有一个选项甚至提供了一个减少 你图片资源的内存占用的功能
那么回到我们的示例app 早些时候我们看到通过使用HEIC 我们能够将app 的体积减少至17.9兆字节
现在 也通过适配资源目录 主要通过app分割功能 我们就能更进一步地将 这个app的内存占用减少 至14.9兆字节
只需简单地使用了 HEIC和资源目录 就比我们开始时减少了40% 的内存占用
所以如果你还没使用HEIC 和资源目录来管理你的图片资源 我们非常推荐你调研使用它们 它们是一个很棒又简单的 方式来获得更高的效率 和更小的app内存占用率
接下来 我想要简单地聊一下 文件系统的元数据
我们示例app包含了一个小的 plist文件来追踪上一次 app被启动的时间 app每次被启动时 我们在plist文件中读取它 更新last_app_launch时间属性 将这个更新后的plist文件 重写回磁盘中
如果我们观察到这个行为表现 像是在使用文件活跃状态仪表 Alejandro将在之后演讲中 介绍关于它的一些信息 我们能看到这个行为导致了一次读取 它很有道理 我们读取了plist文件
但它导致了三个写入操作 你可能会有点吃惊 因为我们只对一个文件进行了写入
我们也看到了一个fsync操作 这些开销很大 为什么那样操作开销会很大 我们之后会介绍更多内容
所以 为什么不是不是一次 而是三次写入呢? 那么 答案就是文件系统元数据
文件系统元数据是我们每次 创建或删除一个文件时 文件系统需要更新的数据 当前案例中 写入了plist文件 创建了文件 这导致了额外的操作
所以什么是文件系统元数据? 文件系统元数据是文件系统 需要追踪的关于我们文件的信息 比如文件名字 尺寸 位置
以及日期 比如创建的日期 或上次修改的时间的信息 还有更多的
为了更好地理解每次 当我们创建一个文件时 文件系统要实现什么 我们来了解一下APFS要做什么 当我们将NSDictionary 文件写入磁盘时
好的 APFS要做的第一件事是 更新文件系统树 它会通过更新它的一个节点来实现
不过 因为APFS的即写即拷性质 我们实际上并未更新一个已有的节点 我们创建了一个已有节点的备份 我们来深入了解一下
这是我们已有的文件系统树
我们看到了一个已有节点的备份
这个新的节点和原始节点 名字怎么不一样了 它其实和原始节点的名字一样 但是新节点增加了内容 或至少增加了不同的事务ID 它的这个不同的事务ID可以让 APFS来支持 高阶的功能 比如截屏
那么返回到上一级 现在我们有了 我们已更新的文件系统树 APFS需要更新这个对象地图 那么它会留意新的节点 那么 总体来说 为了支持写入新的 文件 APFS需要实现两个单独的操作
总共8K的写入I/O
4K用来更新文件系统树 另外4K用来更新对象地图
我们还是需要写入这个文件本身 当前场景下 它虽只是240字节 的NSDictionary数据 我们向一个iOS设备磁盘 能写入的最小的文件大小是4K 所以它被四舍五入了
总体来说 须向磁盘写入12K的 数据存储240字节的NSDictionary
只有大约2%的效率 所以示例不仅向我们展示了APFS 为了跟踪文件创建需要实现的工作 它也高亮了在文件系统的独立文件中 存储量极小的数据的成本
那么 在我们刚看到的示例 我们看到在APFS创建一个文件 需要8K的I/O
那么删除一个文件呢? 它是8K 另一个常见的操作 比如重命名一个文件是16K 修改一个已有文件是8K
这里最重要的是文件系统更新 并不是免费的 事实上 它们涉及到 比数据存储更多的I/O使用量 作为一个结果 关于如何创建 修改和删除文件 我们需要有选择性地操作 我们想要尝试避免高昂的行为操作 比如快速地创建和删除文件
如果我们有一个使用场景 需要在文件系统中保存暂时数据 对于暂存数据来说 这是一个减少系统耗费的一种好方式 首先 创建你的文件 但保持它打开和非接入状态
不要为它调用fsync 这样做会给文件系统一个它需要 在OS缓冲中需要尽可能长时间地 保留暂存文件 以及不要将它可能需要频繁地 写入到磁盘的提示
如果你想要了解更多关于APFS 文件系统的元数据 我们的开发者网站上有一个 很棒的参考文档 我非常推荐你查看它
接下来 同步到磁盘
当它开始管理我们的数据在哪存储时 为了最佳的性能表现 我们想要保存 我们缓存中离CPU最近的数据 但当我们需要它时 我们也想要能够 从磁盘中获取到我们的数据
首先 我们来了解一下我们有的 不同的缓存
首先 这是OS缓存 这是我们为了最佳性能表现想要 保存的我们的数据
对OS缓存进行读写操作 就是前面提到的逻辑I/O 因为这个缓存依靠内存 逻辑I/O操作完成得非常快速 在OS缓存中保存数据通常对 频繁使用和修改数据有利
接下来 我们有了磁盘缓存 磁盘缓存实际上 被物理存储在存储设备上
最后 我们有了永久存储 这实际上是物理媒介 它会长久持续 保存数据 在iOS设备和最新的Mac上 它是NAND
物理I/O在物理存储器上 被读取和写入 这些I/O会抵达或去往磁盘缓存 或永久存储
那么 现在我们已经了解了一些 缓存和持久存储 我们来了解一下最通用的API 我们使用它从OS缓存中移动数据 到存储设备上
首先 是fsync
fsync会让数据从OS缓存中 移动到磁盘缓存
但它不保证数据 将会被立刻永久存储 若软件没有更进一步输入 它会到达设备的固件 来查明数据何时会从磁盘缓存中 被移动到永久存储
它也不能保证写命令 就是说OS缓存中的数据 写入磁盘缓存中的命令 可能不太会和数据被磁盘缓存 写入至永久存储时的命令一样
如果我们过度使用fsync时 它的开销也很大 当我们在OS缓存中有数据时 OS缓存能够轻易地接受 重写或改动同样的数据 只要我们使用了fsync 它会移动至磁盘缓存
基于我们需要保证我们的数据 被移动到磁盘缓存的节奏 手动调用fsync可能并不必要 OS会为我们周期性地实现
从OS缓存中将数据移动至永久存储 最主要的方式是通过F controls的 FFULLFSYNC
这会导致驱动中的磁盘缓存的数据 会被刷新
不过 这会导致磁盘缓存中 所有的数据会被刷新 所以我们不只是想要移动到永久存储 的数据会被移动到永久存储 磁盘缓存中的所有数据都会被移动
最后 它的耗费量很大 因为它可能有很多数据 它会耗费很多时间
再一次 它可能实际上并不需要 手动操作 OS会为我们周期性地实现了
如我们用FFULLFSYNC 最重要的原因是为了保证I/O命令 一个更好更有效的替代方式是使用 F BARRIERFSYNC
F BARRIERFSYNC 强制实行I/O命令
将F BARRIERFSYNC 从根本上作为有着障碍的fsync 可能是最好的思考方法 这个障碍是 一则给Apple SSD执行 在障碍之前收到的所有iOS的提示 在障碍之后才会收到它们
最后 它比F FULLFSYNC 的耗费要小很多 不用将所有磁盘缓存中 的数据存储至永久存储 就得到了我们想要的相同的结果
所以如果你对I/O命令有所顾虑 请用F BARRIERFSYNC 而不是F FULLFSYNC 它是更快速和有效的方式 来访问你在磁盘的数据
序列化的数据文件 序列化的数据文件 文件比如plist、XML 和JSON 它们很棒 它们用起来很方便 它们是存储不常用的修改后的数据 非常好的方式 它们解析起来相当容易
然而 除了所有这些简易操作的方面 它还有一些不足之处
每次我们对这个文件 做出一点改动时 整个文件会被重新序列化 重写至磁盘
结果就是 它们的扩展性不佳
因为它们使用起来非常方便 所以它们很容易被误用
因为只要有一个改动 我们就必须替换这个文件 它们是非常集中的文件系统元数据
它们并不意味着能取代一个数据库
查看文件活跃状态仪表的截图 我们能看到创建 读取和修改plist文件的行为 导致了12次分散的I/O操作 这对于四行代码可能有点多
如果我们在这个有点略微不同的视图 我们会看到每次 我们调用NSDictionary 来自动地写入文件
这个操作同一个fsync 操作一起结束 代表在该NSDictionary 存储的所有数据 我们推送至磁盘 它永远不会 运用OS缓存的好处了
最后 非常大的数据集 或频繁被改动的数据集 它们在一个序列化plist格式中 并不非常有效
如果你的数据量很大 或需要频繁改动 Core Data是很棒的替代品
Core Data管理创建在SQLite上 它提供了一个在SQLite数据源 和你app的模型层之间的 很好的抽象层
Core data自动地管理 对象视图和它们之间的关系
支持变化追踪和通知
自动地版本追踪和多次写入冲突解决 Core Data甚至会自动地 为多个并行操作建立联系
iOS 13新加入的Core Data 支持CloudKit的集成 对于Core Data适配者来说 这是一个很大帮助
Core Data 同时支持实时查询 它允许你快速集成查询 那么 你不必提前手写你觉得你可能 需要的所有的SQLite查询代码
Core Data 也提供了自动内存管理
状态聚合和数据处理
模式迁移和iOS 13新加入的 数据非规范化
等其他更多
我们也观察到了 Core Data的适配者 必须写50%到70%的少量代码 来支持他们的模型视图 那段代码无需写入、修改或调试 不过 如果你有一个使用场景 它需要直接使用SQLite 我们有一些最佳实践想要分享给你
这是一个更大的话题 所以我们有 一些子话题包括连接 日志登载 数据处理 文件大小和隐私 和部分索引
或子连接
SQLite的稳健性保证并不是免费的 打开和关闭一个数据库 会导致相当大的开销操作 比如持续检查 日志恢复和 日志检查和日志检验指示
最后 我们实际上推荐不要使用 一个更传统的数据库模型 来每次按需打开和关闭一个数据库
取而代之 我们推荐相反的方式 让数据库尽可能地一直保存打开 当有必要时才断开链接 对于多线程的处理 建立连接 这样 只要一个线程还需要数据库 数据库就会保持打开状态 这帮助分担了多次打开和 关闭一个数据库成本
接下来 日志登载
删除模式日志登载是SQLite 默认的志登载模式 但它并不是最高效的 为了知道为什么 我们来看一下 删除模式日志登载是怎样工作的
我们有一个数据库 我们想要修改其中的四页
发生的第一件事是 我们复制这四页 到一个日志文件结束后
接下来我们能在数据库中 修改这四页 完成之后 日志文件就会被删除 所以如果我们想一想 我们必须写入两遍 我们需要修改的页面 我们所有的文件系统对这个 只做了一次数据处理的短时间 的日志文件的开销
幸运的是 SQLite为预写日志 或WAL模式日志登载 提供了一个更加高效的替代品 WAL模式日志登载提供了 一个减少写入的好方式 它允许我们在同一页上将 多次写入操作结合在一起 它使用了更少的障碍物 它能同时支持多个读入和写入操作 以及支持截屏
我们来看一下WAL模式日志 是如何工作的
所以再一次 我们有一个数据库 我们想要修改其中的四页 它们被写入预写日志文件 而不是直接地在数据库中修改 以及 我们有了额外的数据处理 这些页面也被添加至 预写日志文件里了 直到预写日志文件变得相当大之后 它才会为它开始检查点
当我们为它开始检查点时 我们能使 用WAL模式的很多优点中的一个 在删除模式数据库里 还没被多次修改的页面 所有这些在同一页面的改动 在WAL检查点的工程中被合并了 同一页面只需被写入一次
当我们完成后 一个简单的 WAL文件的标题重写 是所有将来所需用到的 因此要减少文件系统维护这个 预写日志文件的成本
多数SQLite的使用场景中 我们可以看到WAL模式更加高效 如果你还没为SQLite数据库 使用WAL模式 我们非常建议你切换至WAL模式 它是为你的app提升性能 的很好的方式
使用多次插入 更新和删除声明 在一次数据处理中是为SQLite 提供更多信息的一个很好的方式 这样它能更有效地为你运行
通过多次声明 在相同的数据处理下 被多次修改的文章 只会在磁盘中被写入一次
在这个示例中 我们有三次单独数据处理 每一个都在数据库中修改相同页面的 一项声明 我们会看到数据库中的同一页面 被修改了三次
不过 如果我们在这三个声明中 对其中一个的数据做修改 所有的这些改变会被结合在一起 以及数据库中的页面 只会被重写一次
最后 在单个SQLite 数据修改中使用多次声明 是聚合多次变动的一个很好的方式
文件大小和隐私
所以当我们在数据库中删除数据时 会发生什么呢? 空间包含了被标记为 被删除的空闲数据 当它不再是数据库的一部分时 从技术角度来看 它其实仍在磁盘上
所以如果我们要如何更高效 安全地删除敏感信息?
我们推荐使用 secure_delete=Fast secure_delete=Fast 非常好用
它自动地清理被删除的数据 对于相同页面数据并没有成本损失 我们在头文件中修改过的 用来标记空闲数据 现在它也是iOS 13中 SQLite的默认行为表现了 如果你需要它来创建老版本的iOS 请注意secure_delete=FAST 的编译指示
当它被用来管理 我们数据库文件的大小时 我们强烈建议你 不要使用VACUUM
VACUUM是一个非常慢的内存 以及I/O的密集型操作 为了更好理解为什么 我们来看看 VACUUM是如何为SQLite 数据库工作的
那么 假如我们有一个数据库 我们想要清除所有的空闲页面
发生了什么呢?我们最后为我们的 数据库打开一扇缓存的门 创建了一个日志文件 接下来 我们结束了一个从数据库 到日志文件的SQLite转储 为我们的数据库拷贝了所有 的有效数据至日志文件
接下来 当为日志文件实行 检查点时 为了符合日志文件的大小 数据库将被删减 日志中的所有数据都会被重新插入 到数据库
接下来当它完成时 日志文件会被丢弃
如我们看到的 这个开销很大 我们数据库中的这些 所有有效数据都被至少写入了两次 一次被写入到了日志文件 接着再一次回到了数据库
如果数据库工作的这一边太大 而不能放置内存中 SQLite其实会利用多余的文件 帮助管理额外的数据 直到操作完成
很幸运 SQLite中有很多 更有效的替代品 在当前情况下 就是 auto_vacuum=INCREMENTAL auto_vacuum的增量很棒 因为它不仅允许我们更高效地 管理数据库文件的大小 它还让我们确认页数 我们想要清空数据库 为数据库保留之后会用到的 空闲页数提供一个选项
我们来看一下auto_vacuum=INCREMENTAL 是如何工作的
那么 在这个例子中 我们会清空 两个页面 然而 当我们从WAL文件的 数据库中 移出我们所有的数据之前
为了增量自动清理 我们要做的是转移数据库最后 的两页到预写日志 在调整数据库树的时候 任何被修改的父节点 也会被写入预写日志
接下来 当预写日志获得了检查点
数据库文件本身会被删除
我们从数据库的最后迁移的页面 将会去到之前的空闲页面 任何被更新的父节点会被写入到 数据库中 那么 就像你看到的 在我们必须将我们的数据移入 和移出数据库之前 现在我们简单地 在数据库中修改页面的一个子集 这非常有效率
最后 我们相当推荐使用 增量自动清理 通过快速安全地删除 来管理你的SQLite 数据库文件大小和隐私
部分索引
索引很棒 索引允许更快的排序分组 和WHERE查询子句 不幸的是 他们不能被免费使用 数据库需要支持索引 这些会有一定量的开销 在我们添加了更多的索引之后 每个新写入到数据库的数据开销 会更大
幸运的是 它有更有效率的 部分索引形式的替代品 部分索引允许你使用WHERE 查询子句来描述你想要索引 这很棒 因为现在你能获取到 一个索引的益处了 当你想要它 但又不想为索引 付出没有必要的代价 当它不能为你带来任何好处时
那么 SQLite的总结
请尽可能长时间保持数据库连接打开
使用WAL日志登载模式 而不是删除日志登载模式
可能的话 在每个数据处理时 使用多次声明 这是SQLite为我们做的优化
使用快速安全删除和自动清理增量 来同时管理你数据库的 文件大小和隐私
如果可行的话 使用部分的索引 而不是一般的常规索引
如果你真的不关心SQLite 的这些细节 我们强烈建议你 只使用Core Data Core Data为你解决了 所有的这些难题 因为Core Data 已被多次改进 Core Data的适配者 也会免费得到这些好处
接下来 Alejandro 将为我们展示如何使用 最新版的文件活跃状态仪表 为我们展示现实世界中我们应该 如何为app剖析和优化I/O Alejandro
(文件活跃状态仪表)
好的 谢谢Kai 大家早上好 欢迎大家参加本次关于优化内存 的演讲
我想介绍我们对 文件活跃状态仪表 所做的一些提升 来看看我们如何使用它 优化我们的app的存储空间 那么我们开始吧 文件活跃状态仪表有哪些改变?
我们做的第一件事是为所有的 Apple设备增加了支持 所以这意味着你可以使用 统一的分析经验 在你的iOS设备 Mac Watch TV等等
文件活跃状态仪表也允许你 追踪除了你自己的app之外 还有整个系统 这样你就能看到你的app的行为 只针对I/O的子系统 以及它如何同剩下的系统交互 这样你能看到正在进行中的不同交互
接下来 Kai提到过的 逻辑和物理I/O之间是有差别的 了解它们是如何相互交互的 实际上对了解 你的I/O使用量是非常重要的 文件活跃状态仪表让我们 可以将它们结合在一起查看
最后 我们也添加了 对自动推理的支持 自动推理有各种不同的机制 那么我想要非常简短地介绍一下它
首先 自动推理的其中一个是 反模式检测 我们添加它实际上是想要过度的 物理权利 那么当你在追踪时 文件活跃 状态仪表若监测到了你app中的 一些过度活动行为时 它实际上会提示你 你可以从仪表中直接跳转 来查看是什么导致它发生的
当查看某个I/O相关的系统 的直接调用或是你自己的调用时 我们对此也加入了支持 因为这个框架已经失败了 这些是需要了解的重要的内容 除了I/O之外 你app中的正确性也同样重要
最后 Kai提到过F FULLFSYNC的 fsync和F control 我们也有一个检查次优缓存的机制 这样你就能看到 你的app可能会 表现出某些行为是因为 没有非常好地利用OS缓存 那么我们从文件活跃状态仪表开始 来看它是什么样子的
使用Instruments 11 当我们打开 Instruments 我们看到 文件活跃状态的图标还是和之前相似 但在底部多了一行新的字符 这是它所能做的一个总结
如果我们接下来选择它 我们看到了一些新的轨道 首先是文件系统建议行踪 这个轨道是所有的这些反模式 和自动推理建议的行踪
在它下面 我们有文件系统活跃状态 文件系统活跃状态会打断逻辑的读取 逻辑的写入 它会为你展示这些操作发生次数 的数量 你也能更深入地了解调用的次数 谁调用了它们 和某些其他的统计 相似地 在磁盘使用量的正下方 你可以看到相同的读入和写入差别 除了物理的层级之外 最后 磁盘I/O的延时 这样我们能看某些物理 I/O的时长 那么 我们开始吧 我们回到这个示例app 我想实现的第一件事实际上是 为照片标记最爱 那么 在这些图片中 每个右侧底部都有一个星星 我想要实现的是能选择那个星星 来标记一张图片为最爱 比如 我能选择一张香蕉蛞蝓图片 为我的最爱
这些摩天大楼也是 我会做的第一步是 每次当我们标记一张为最爱时 通过打开和关闭数据库来实现 Kai讲过这不是最佳的实现方案 但我还是觉得将它导入到文件 活跃状态仪表轨迹中很实用 我们有一条基线 我们能看到正在发生的一些事情
在我后面 的确是那样 我运行文件活跃状态仪表 每次操作时通过打开 和关闭数据库对照相同的工作流 我想要关注磁盘使用量的第一条轨迹 因为这是所有物理的 I/O信息所在的地方 我们在物理地写入列 或物理地写入行中看到 我们看到物理I/O的数量不一致 在当前情况下 在工具提示文字中 这个特别的列有54个 但在它的正下方是详情视图 详情视图是所有额外的统计信息 所在的地方 那么我将进到这里 这样我们能看到我们获取到 的一些东西
通过放大 我想要知道 这个工作流中的最爱照片 每次操作通过打开和关闭数据库 我们有1,002次不同的 物理I/O操作 总共占有低于6兆字节的内存 这看上去没有很多 但当我们和其他的相比 我们能更好地了解 为什么这个如此糟糕 那么这里我们有一些关于 延时和平均延时的统计信息 但我想要切换回总视图 因为我也注意到 在文件系统建议轨道中 我们有一些仪表给我们的通知 我想要进到里面 这样我们就能看到发生了什么 在底部 我们的详情视图 这里的详情视图的数量列 告诉我们一共有12条通知
如果我们到下拉框 我们会看到这些通知 是过度物理写入的精准描述 我们知道打开和关闭数据库不一定 是一件好事 我们将要尝试其他技术来实现 但我想从这个有着12则 文件系统通知的基线开始 文件活跃状态仪表
最后 我也想要聊一下 实际的文件系统活跃状态轨迹 我们能从中看到被调用的操作的 统计信息 比如写入和读入等等 但在这个表格这里 我们也获取到了我们app的 不同的逻辑的I/O视图 这里默认是文件系统统计信息 但我们也能找到下面的 文件描述符信息
好的 记住这一点 现在我要切回 到一个不同的模式 它会按需打开和关闭数据库 特别地 我会回到磁盘 使用量详情视图 我想要做的第一件事是 我们从1,002次物理I/O操作 跌到至54次 我们从6兆字节 的磁盘占有量 跌到288千字节 它的效果非常明显 当我们打开和关闭我们的数据库时 只用改变使用量模型就能轻易实现
更进一步 再次关注文件系统建议 我们从之前这么做的时候 是从12开始的
但现在我们只有3个了 这个还不是最理想的使用方式 我们还可以进一步优化 我们实现了不同的行为表现比如 日志登载 我们会看到这个数字改变
说到这 我们来开始介绍删除模式 日志登载 就像Kai提过的 删除模式日志登载 是SQLite默认设置 所以这里的这个统计页面和我之前 按需打开和关闭数据库所 展示的那个一样 所以我不会再展示整个轨迹 但我想要回收这些数字 54物理I/O操作 一共是288千字节
但当我们切换至使用WAL 模式日志登载的模型时 我想要讲一下一些有趣的现象
首先 现在我们在文件系统 建议轨道上有0个建议 我们之前有12条 最后变为3个 现在是0个 我们只是简单地使用了WAL模式 日志登载就做出了非常巨大的优化
我想讲的第二点是逻辑的 和物理的I/O之间的交互 特别要说的是 在这里的文件活跃状态轨道 我们看到了很多逻辑I/O 但没有看到一个物理I/O 直到我们停止app的轨迹 这为什么重要呢? 当我们和之前实现的比较时 使用删除模式日志登载 注意在删除模式日志登载里 每次我们有了文件系统活跃状态 逻辑I/O也是 我们也有了一个和它 相应的物理I/O 然而使用WAL模式日志登载 它非常好地利用了OS缓存 为我们提供了很多很棒的性能表现
想要更为仔细地了解它 我们能再一次回到文件系统活跃轨迹 关注详情视图
使用WAL模式日志登载 我们只有一个fsync调用 然而使用删除模式日志登载 我们一共有16个 所以WAL模式非常好地利用了 OS缓存的优势
接下来 我想讲的是我们如何实现 删除照片功能 我们讲过设置最爱 但我们也需要在app中移除 照片 我们要讲的第一件事是 调用单个声明数据处理 Kai也提到过的 特别地 当我们想要选择删除一张 照片 我们会选择左下脚的符号 我们会向数据库发送 一条删除查询语句 现在我们可以将这认为是一个 单个声明数据修改 因为我们在每张照片执行 这条删除查询 我们自己不会做任何合并
使用这个模型 这里的单个声明数据修改方式 我们也使用一些文件系统活跃状态 就和一些磁盘使用量一样
但值得关注的一点是这个方式 我们有111次不同的文件系统操作
到达磁盘使用量轨道 我们有12次写入 总共有72千字节的内存占用
接下来 我想要聊一下多次声明 数据修改 通过这些照片中的每一个 甚至是一个逻辑的视角 我们不想一次只删除这些照片中 的一个 合乎逻辑地 我们想要将它们 一次全部删除 我们为它使用SQLite 做了一种模拟 通过合并所有这些删除声明至一次 数据修改 所以我们在一个单次的数据修改中 做了多次声明 如果我们这样做 我们减少到了37次文件系统操作 所以我们显著地减少了工作量
除此之外 如果我们 查看磁盘使用量 我们的写入减少到了4个 内存减少至了24千字节
把它们并排一起看 我们开始一共有111次单个 声明数据修改的文件系统活动 我们使用多次声明数据修改 减少到了37次 回到这个这个是如何 转换到实际的物理的磁盘使用量 我们开始时有12次写入 一共72千字节 现在我们使用多次声明数据修改 减少至只有4次写入 一共24千字节
因为我们在介绍关于删除的话题 我们也应该了解清除 应为我们想保持我们的数据 被压缩 或尽可能紧凑 我们从一个全面的清理开始了解 在当前使用案例中 每次当我们 发出一条删除声明时 我们会发出一条清理声明 Kai告诉过我们全面清理 并不是实现它的最佳方案 但我们能看到它在文件活跃状态仪表 实际上是如何工作的
特别地 通过实现这个 我们一共有27次不同的I/O操作 发出一条全面的清理 使用了一共168千字节
但如果我们切换至使用增量清除呢
我们有一些不同的数字 我们为72千字节的存储占用 一共实现了12次I/O操作
再一次 把它们并排看 使用一个全面清理 I/O操作是27次 使用增量清理 I/O操作下降到了12 从全面清除的168K的总磁盘占用 减到了72 通过在SQLite中使用这些模式 它获取了颇多利益
那么 我现在想要总结一下 第一点是我想要你 吸取这些教训 无论你是在使用Core Data SQLite或plist等等 我们想要你吸取这些教训 但也不只是这样 我们也希望你能使用文件 活跃状态仪表来验证它们 现在文件活跃状态仪表可能会 通过提供这些功能来帮你 但你可能有其他的一些 你甚至不知道的建议 文件活跃状态仪表 会将它们以可视化的方式提供给你 让你留意它们
记住这些 我们也希望你能持续 优化内存 除了眼前的这些内容之外还有更多 我们希望这些教训和 我们提供的这些工具 能为每个人带来好的体验
想要了解更多信息 今天晚些时候 我们会有一个关于性能的实验室 今年的WWDC 我们还有一个演讲是 关于使用Core Data 来创作app 如果你想要了解更多 关于如何使用它的话
感谢大家参加 请好好享受接下来的演讲
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。