持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第15天,点击查看活动详情
内存管理基础
android 給每个app分配一个VM,让app运行在dalvik上,这样即使app奔溃也不影响到系统。系统给vm分配一定的内存大小,app可以申请使用的内存大小不能超过此硬性逻辑限制,就算物理内存富于,如果应用超出vm最大内存,就会出现内存溢出crash。
由程序控制操作的内存空间在heap上,分java heapsize和 native heapsize
- java申请的内存在vm heap上,所以如果java申请的内存大小超过VM的逻辑内存,就会出现内存溢出的异常。
- native层内存申请不受限制,native层受native process对内存大小的限制。
内存指标概念
| Item | 含义 | 等价 |
|---|---|---|
| USS | 物理内存 | 进程独占的内存 |
| PSS | 物理内存 | PSS = USS + 按比例包含共享库 |
| RSS | 物理内存 | RSS = USS + 包含共享库 |
| VSS | 虚拟内存 | VSS = RSS + 未分配实际物理内存 |
VSS >= RSS >= PSS >=USS,但/dev/kgsl-3d0部分必须考虑VSS
内存分配
Android的Heap空间是一个 Generational Heap Memory 的模型,最近分配的对象会存放在 Young Generation 区域,当一个对象在这个区域停留的时间达到一定程度,它会被移动到 Old Generation ,最后累积一定时间再移动到 Permanent Generation 区域
1、Young Generation
由一个Eden区和两个Survivor区组成,程序中生成的大部分新的对象都在Eden区中,当Eden区满时,
还存活的对象将被复制到其中一个Survivor区,当次Survivor区满时,此区存活的对象又被复制到另一
个Survivor区,当这个Survivor区也满时,会将其中存活的对象复制到年老代。
2、Old Generation
一般情况下,年老代中的对象生命周期都比较长。
3、Permanent Generation
用于存放静态的类和方法,持久代对垃圾回收没有显著影响。
总结:内存对象的处理过程如下:
- 对象创建后在Eden区。
- 执行GC后,如果对象仍然存活,则复制到S0区。
- 当S0区满时,该区域存活对象将复制到S1区,然后S0清空,接下来S0和S1角色互换。
- 当第3步达到一定次数(系统版本不同会有差异)后,存活对象将被复制到Old Generation。
- 当这个对象在Old Generation区域停留的时间达到一定程度时,它会被移动到Old Generation,最后累积一定时间再移动到Permanent Generation区域。
系统在Young Generation、Old Generation上采用不同的回收机制。每一个Generation的内存区域都有固定的大小。随着新的对象陆续被分配到此区域,当对象总的大小临近这一级别内存区域的阈值时,会触发GC操作,以便腾出空间来存放其他新的对象。 执行GC占用的时间与Generation和Generation中的对象数量有关:
- Young Generation < Old Generation < Permanent Generation
- Gener中的对象数量与执行时间成正比。
4、Young Generation GC
由于其对象存活时间短,因此基于Copying算法(扫描出存活的对象,并复制到一块新的完全未使用的控件中)来回收。新生代采用空闲指针的方式来控制GC触发,指针保持最后一个分配的对象在Young Generation区间的位置,当有新的对象要分配内存时,用于检查空间是否足够,不够就触发GC。
5、Old Generation GC
由于其对象存活时间较长,比较稳定,因此采用Mark(标记)算法(扫描出存活的对象,然后再回收未被标记的对象,回收后对空出的空间要么合并,要么标记出来便于下次分配,以减少内存碎片带来的效率损耗)来回收。