本文是对官方视频 浅谈Unity内存管理 (一个干货满满的视频)的一个整理。
什么是内存?
操作系统有物理内存和虚拟内存两个概念:
物理内存
物理内存也就是我们真是的硬件设备,例如内存条。
访问过程缓慢
我们需要知道,CPU访问内存是一个慢速过程,访问过程具体为:先访问Cache(L1,L2,L3),若全没找到再去访问内存,接着把找到的数据存放到Cache中,完成一次操作。在Cache中没有找到数据,我们称之为Cache Miss。因此过多的Cache Miss就会导致大量的内存和Cache的IO交换,浪费大量时间。
因此我们需要尽量减少Cache Miss,来提高访问速度,Unity为此提出了ECS和DOTS方案,有兴趣的小伙伴可以看看之前有关ECS介绍的文章,它们可以将存储在内存中的不连续数据,变为连续的数据。
台式设备和移动设备内存架构的差异
1.首先移动设备没有独立显卡。
2.移动设备没有独立显存(显存的作用是用来存储显卡芯片处理过或者即将提取的渲染数据),所有在移动端数据内存和显存是同一块内存。所以有可能我们游戏占用的内存并不大,但是依旧爆内存了,其实是因为显存分配不出来了。这种情况,我们可以去查看一下Log,例如Android会有一个 OpenGL Error:Out Of Memory。
3.移动设备的CPU面积更小,因此会导致缓存级数更少,大小也更小,例如一般的台式机三级缓存可能有8-16M,而移动设备则只有2M左右。
虚拟内存
虚拟内存是利用磁盘空间虚拟出的一块逻辑内存,用作虚拟内存的磁盘空间被称为交换空间(Swap Space)。
内存交换
操作系统在使用内存不够的情况下,会尝试把一些不用的内存(Dead Memory)交换到硬盘上,从而节省出更多的物理内存。这个操作我们称之为内存交换,它会占用大量的硬盘空间。
然而移动设备不做该操作,因为移动设备的IO速度很慢,而且移动设备的可存储物(例如sd卡,内存芯片等)的可擦写次数也比硬盘少很多,会影响使用寿命。
内存压缩
在IOS中(Android没有)会将不活跃的内存压缩起来存储到一个特定空间里,来节省出物理内存空间,来给活跃的app使用,这个操作称之为内存压缩。(可以查看XCode的Virtual Memory)
内存寻址范围
内存寻址范围也称寻址空间,指的是CPU对于内存寻址的能力(最大能查找多大范围的地址)。数据在内存中存放是有规律的,CPU在运算的时候需要把数据提取出来就需要知道数据在那里,这时候就需要挨家挨户的找,这就叫做寻址,但如果地址太多超出了CPU的能力范围,CPU就无法找到数据了。
内存寻址范围和Memory Controller(内存控制器)有关,和运算位数(32位或64位)无直接关系。当然一般情况下,64位的CPU寻址范围更大。
Android内存管理
基本单位Page
Android是基于Linux操作系统,其内存基本单位称为:Page,默认4K为一个page。因此内存回收和分配的时候一般已4k进行处理,但是并不意味着所有的数据都是4k对齐的。
用户态和内核态
Android内存分用户态和内核态:
用户态:只能受限的访问内,所有app都是运行在用户态上的。
内核态:cpu可以访问内存的所有数据。
内核态的内存,用户态是严格不许访问的,例如一些Error Access,可能是指针飘到内核态上了。
内存杀手
Android有一个内存管理工具:Low Memory Killer,当内存不足时,会清理内存,在Android上常见的一些后台app消失,一些手机服务消失,手机重启或者是app崩溃闪退等都和它有关。
Android应用分层
首先我们来了解下Android的应用分层,这也是杀手的追杀路线(会从最底层往上杀)
Native | 系统内核,例如adbd |
System | 系统级应用,例如system server |
Persistent | 用户级应用,例如电话,蓝牙,wifi |
Foreground | 前台应用,当前正在使用的Activity |
Perceptible | 辅助类应用,例如搜索,音乐,键盘 |