- Zygote Space
用来管理Zygote进程在启动过程中预加载和创建的各种对象,Zygote Space中不会触发GC。
在Zygote进程和应用程序进程之间会共享Zygote Space。在Zygote进程fork第一个子进程之前,会把Zygote Space分成两个部分,原来的已经被使用的那部分堆仍叫Zygote Space,而未使用的那部分堆就叫做Allocation Space
- Allocation Space
之后的对象都会在Allocation Space上进行分配和释放。Allocation Space不是进程间共享的,在每个进程中都独立拥有一份。
- Card Table
用于DVM Concurrent GC,当第一次进行垃圾标记后,记录垃圾信息
- Heap Bitmap
有两个Heap Bitmap,一个用来记录上次GC存活的对象,另一个用来记录这个GC存活的对象
- Mark Stack
DVM的运行时堆使用 标记-清除算法进行GC,Mark Stack就是在GC的标记阶段使用的,它用来遍历存活的对象。
[]( )1.4 DVM的GC日志
DVM和ART的GC日志与JVM的日志有很大的区别。
在DVM中每次垃圾的收集都会将GC日志打印到logcat中,具体的格式为:
D/dalvikv: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
可以看到DVM的日志共有5个信息,其中GC Reason有很多种,这里将它单独拿出来进行介绍。
1.引起GC的原因
GC Reason 就是引起GC的原因,有以下几种。
-
GC_CONCURRENT:当堆开始填充的时,并发GC可以释放内存
-
GC_FOR_MALLOC:当内存堆已满时,App尝试分配内存而引起的GC,系统必须停止App并回收内存。
-
GC_HPROF_DUMP_HEAP:当你请求创建HPROF文件来分析堆内存时出现的GC
-
GC_EXPLITCIT:显示的GC。例如调用
System.gc()
- GC_EXTERNAL_ALLOC:仅适用API<=10,且用于外部分配内存的GC
2.其他的信息
- Amout_freed
本次GC释放内存的大小
- Heap_stats
堆的空闲内存百分比:(已用内存)/(堆的总内存)
- External_memory_stats
API<=10的内存分配 (已分配的内存)/(引起GC的阈值)
- Pause time
暂停时间,更大的堆会有更长的暂停时间。并发暂停时间会显示两个暂停时间,即一个出现在垃圾收集开始时,另一个出现在垃圾收集快要完成时。
3.实例分析
拿logcat中的GC举个例子:
D/dalvikvm: GC_CONCURRENT freed 2012k, 63% free 3213K/9291K, external 4501K/5161K, paused 2ms+2ms
意思就是:引起GC的原因是GC_CONCURRENT,本次GC释放的内存为2012KB,堆的空闲内存百分
比为63%,已经使用内存为3213K,堆的总内存为9291K,暂停的总时长为4ms
[]( )2.ART虚拟机
=========================================================================
ART在Android5.0完全取代了DVM
[]( )2.1 ART与DVM的区别
- DVM中应用每次运行时,字节码都需要通过JIT编译为机器码,这会使得应用程序的运行效率降低,而在ART中系统在安装应用程序时会进行一次
AOT(ahead of time compilation,预编译)
,将字节码预先编译成机器码并存储在本地,这样应用程序每次运行程序时就不需要执行编译了,运行效率大大的提高了。设备的耗电量也会降低。
采用AOT预加载也有两个主要的缺点:
一是AOT会使得应用程序的安装时间边长
二是字节码预先编译成机器码,机器码需要存储空间会更多一些(这里就是空间换时间了)
为了解决上面的缺点,在Android7.0的版本中ART加入了JIT,作为AOT的一个补充,在应用程序安装时并不会将字节码全部编译成机器码,而是在运行中将热点代码编译成机器码,从而缩短应用程序的安装时间并节省了存储空间。
-
DVM是为32位CPU设计的,而ART支持64位并兼容32位CPU,这也是DVM被淘汰的主要原因之一
-
ART对垃圾回收机制进行了改进,比如更频繁的执行GC,将GC暂停由两次减小为一次
- ART的运行时堆空间划分和DVM不同
[]( )2.2 ART的运行时堆
与DVM的GC不同的是,ART采用了多种垃圾收集方案,每个方案会运行不同的垃圾收集器,默认采用的是CMS(Concurrent Mark-Sweep)方案,该方案主要是使用了 sticky——CMS和 partial-CMS,根据不同的CMS方案,ART的运行时堆的控件也会有不同的划分,默认是由4个Space和多个辅助数据结构组成的。4个Space分别是 Zygote Space、Allocation Space、Image Space和Large Object Space。 前两个和DVM中的作用是一样的。
- Image Space
用来存放一些预加载类
- Large Obejct Space
用来分配一些大对象(默认大小为12KB)
其中Zygote Space和Image Space是进程间共享的空间。
除了这四个Space,ART的Java堆还包括两个 Mod Union Table,一个Card Table,两个 Heap Bitmap、两个Object Map以及三个Object Stack
[]( )2.3 ART的GC日志
ART的GC日志和DVM不同是,ART会为那些主动请求的垃圾收集事件或者认为GC速度慢时才会打印GC日志。
GC速度慢是指GC暂停时间超过5ms或者GC持续时间超过100ms。如果App未处于可察觉的暂停进程状态,那么它的GC不会被认为是慢速的。
ART的GC日志具体格式为:
I/art: <GC_REASON> <GC_NAME> <Objects_freed>(<Size_freed>) AllocSpace Objects,
<Large_objects_freed>(<Large_object_suze_freed>) <Heap_stats> Losobjects,
<Pause_time(s)>
1.引起GC原因
ART引起GC的原因要比DMV多一些
- Concurrent
并发GC,不会使App线程暂停,该GC是在后台线程中进行的,并不会组织内存分配
- Alloc
当内存已满时,App尝试分配内存而引起的GC,这个GC会发生在正在分配内存的线程中
- Explicit
App显示的请求垃圾收集,例如调用System.gc()
。
但是我们要避免的去显示调用GC,应该信任GC。显示的调用GC会阻止分配线程并不必要的浪费 Cpu周期。如果显示地请求GC导致其他线程被抢占,那么有可能导致jank(App同一帧画了很多次)
- NativeAlloc
Native内存分配时,比如为Bitmaps或者RenderScript分配对象,这会导致Native内存压力,触发GC
- CollectorTransition
由堆转换引起的回收,这是运行时切换GC而引起的。收集器转换包括将所有对象从空闲列表空间复制到碰撞指针空间,当前,收集器转换紧在以下情况下出现:在内存较小的设备上,App将进程状态从可察觉的暂停暂停状态变更为可察觉的非暂停状态
- HomogeneousSpaceCompact
齐性空间压缩是指空间列表到压缩的空闲列表空间,通常发生在当App已经移动到可察觉的暂停进程状态时。这样做的主要原因是减少了内存使用并对堆内存进行了碎片整理。
- DisableMovingGc
不是真正触发GC的原因,发生并发堆压缩时,由于使用了GetPrimitiveArrayCritical
,收集会被阻塞,在一般情况下,强烈建议不要使用GetPrimitiveArrayCritical
,因为他在移动收集器方面具有限制
- HeapTrim
不是触发GC的原因,收集会一直被阻塞,一直到堆内存整理完毕。
2.垃圾收集器名称
GC_NAME指的是垃圾收集器名称
- Concurrent Mark Sweep(CMS)
CMS收集器是一种以获取最短收集暂停时间为目标的收集器
采用了标记-清除算法,它是完整的堆垃圾信息,能释放除了Image Space外的所有的空间。
- Concurrent Partial Mark Sweep
部分完整的堆垃圾收集器,能释放除了Image Space和Zygote Space外的所有空间
- Concurrent Sticky Mark Sweep
最后笔者收集整理了一份Flutter高级入门进阶资料PDF
以下是资料目录和内容部分截图
里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。