Android在4.4以前一直使用的Dalvik虚拟机做为App的运行VM的, 4.4中引入了ART做为开发者备选, 5.0起正式将ART做为默认VM了.html
咱们首先来简单了解下两者:android
若是只是想简单了解, 我的以为百度百科上这个Dalvik的介绍基本就知足要求了.shell
若是你们想深刻, 能够看下老罗的Android之旅中Dalvik的相关博文, 从代码层面上分析了Dalvik的启动, 运行机制等. 值得一看.缓存
须要说明的是, Dalvik采用的是JIT技术, 在应用程序启动时, JIT经过进行连续的性能分析来优化程序代码的执行, 在程序运行的过程当中, Dalvik在不断的进行将字节码编译成机器码的工做.bash
ART 取自 Android RunTime. Android用其取代Dalvik, 主要目的就是为了提高运行性能. 因此, ART相比Dalvik有几个关键的提高:网络
在安装apk的过程当中, ART会使用dex2oat程序全部的字节码预编译成了机器码. 应用程序运行过程当中无需进行实时的编译工做, 只须要进行直接调用. 故而提升了应用程序的运行效率.并发
ART和Dalvik都是使用paging和memory-mapping(mmapping)来管理内存的. 这就意味着, 任何被分配的内存都会持续存在, 惟一的释放这块内存的方式就是释放对象引用(让对象GC Root不可达), 故而让GC程序来回收内存.app
对于每一个App进程来讲, Heap内存被限制在一个虚拟的内存区间内. 且定义了逻辑上的使用的Heap Size, 这个Heap Size在系统限制的最大值以内是随着应用的使用状况而变化的.函数
Heap内存的逻辑大小和实际物理内存的大小是不相同的. 后面咱们在使用Memory Monitor等内存分析工具分析内存时, 会看到一个叫作Proportional Set Size (PSS)的值, 这个值才是系统认为的你的App所占用的物理内存大小.工具
这个PSS值也就是实际物理内存大小, 统计包括了你的应用进程所占用的内存大小, 和共享内存中占用的内存大小(比例分配方式计算).
Android VM不会压缩Heap内存的逻辑大小, 故而没法经过碎片整理的方式来释放Heap空间, 而只能经过回收Heap尾部的空内存块来压缩逻辑内存大小.
这时, 咱们的GC就出场了, GC以后, VM会遍历Heap找到不被使用的pages, 经过madvise函数将其返回给内核, 从而释放这块被逻辑Heap使用的物理内存.
Android是一个多任务系统, 为了保证多任务的运行, Android给每一个App可以使用的Heap大小设定了一个限定值.
这个值是系统设置的prop值, 系统编译时内置的, 保存在system/build.prop中. 通常国内的手机厂商都会作修改, 根据手机配置不一样而不一样, 能够经过以下命令查看:
$ adb shell shell@hwH60:/ $ cat /system/build.prop
以手头的Huawei 荣耀6为例, heap size相关的prop以下:
dalvik.vm.heapstartsize=8m dalvik.vm.heapgrowthlimit=192m dalvik.vm.heapsize=512m dalvik.vm.heaptargetutilization=0.75 dalvik.vm.heapminfree=2m dalvik.vm.heapmaxfree=8m
其中:
dalvik.vm.heapstartsize
-- App启动后, 系统分配给它的Heap初始大小. 随着App使用可增长.
dalvik.vm.heapgrowthlimit
-- 默认状况下, App可以使用的Heap的最大值, 超过这个值就会产生OOM.
dalvik.vm.heapsize
-- 若是App的manifest文件中配置了largeHeap属性, 以下.则App可以使用的Heap的最大值为此项设定值.
<application android:largeHeap="true"> ... </application>
dalvik.vm.heaptargetutilization
-- 当前理想的堆内存利用率. GC后, Dalvik的Heap内存会进行相应的调整, 调整到当前存活的对象的大小和 / Heap大小 接近这个选项的值, 即这里的0.75. 注意, 这只是一个参考值.
dalvik.vm.heapminfree
-- 单次Heap内存调整的最小值.
dalvik.vm.heapmaxfree
-- 单次Heap内存调整的最大值.
也能够直接使用getprop查看单项prop:
$ adb shell getprop dalvik.vm.heapsize 512m
Android 系统会尽量长时间地保持应用进程, 但为了新建进程或运行更重要的进程, 最终须要清除旧进程来回收内存. 为了肯定保留或终止哪些进程, 系统会根据进程中正在运行的组件以及这些组件的状态, 将每一个进程设定了一个重要级别. 必要时, 系统会首先消除重要性最低的进程, 而后是重要性略低的进程, 依此类推, 以回收系统资源.
依据重要程度从大到小依次分为5级:
前台进程
用户当前操做所必需的进程. 若是一个进程知足如下任一条件, 即视为前台进程:
只有在内在不足以支持它们同时继续运行这一万不得已的状况下,系统才会终止它们。 此时,设备每每已达到内存分页状态,所以须要终止一些前台进程来确保用户界面正常响应。
可见进程
没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 若是一个进程知足如下任一条件,即视为可见进程:
服务进程
正在运行已使用 startService() 方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,可是它们一般在执行一些用户关心的操做(例如,在后台播放音乐或从网络下载数据)。所以,除非内存不足以维持全部前台进程和可见进程同时运行,不然系统会让服务进程保持运行状态。
后台进程
包含目前对用户不可见的 Activity 的进程(已调用 Activity 的 onStop() 方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。 一般会有不少后台进程在运行,所以它们会保存在 LRU (最近最少使用)列表中,以确保包含用户最近查看的 Activity 的进程最后一个被终止。若是某个 Activity 正确实现了生命周期方法,并保存了其当前状态,则终止其进程不会对用户体验产生明显影响,由于当用户导航回该 Activity 时,Activity 会恢复其全部可见状态。
空进程
不含任何活动应用组件的进程。保留这种进程的的惟一目的是用做缓存,以缩短下次在其中运行组件所需的启动时间。 为使整体系统资源在进程缓存和底层内核缓存之间保持平衡,系统每每会终止这些进程。
当用户切换App时, 被切换到后台的App所使用的内存并未所以删除, 该App进程被缓存到一个LRU缓存中, 以便用户切换回来时, 能更快的启动App, 让多任务更流畅.
可是, 当系统内存不够用的时候, 就会根据LRU特性, 以及上面说到的进程级别(同时也会考虑该App进程占用的内存大小)来决定杀死哪些进程, 来回收内存, 以便执行当前任务.
因此, 若是咱们为了避免要让系统kill掉咱们的App, 能够从进程级别, 内存消耗量等几个方面进行优化.
本文加上GC那些事儿, 咱们讲了两篇的理论知识, 相信你们对Android的内存管理有了个大致的了解, 后面将介绍一些内存分析工具以及使用, 结合实际来讲明怎么分析内存问题.