A. Android 内存管理机制是怎么样的呢
“安卓内存管理机制”理论上看起来很好,可实际呢?
自从看了“安卓内存管理机制”,我也不杀进程了,说是快速启动,最后是不管启动什么程序,卡得跟老太太走路似,真受不了。还有那个说什么内存用满了会自动杀一些没用的进程,没错,会杀进程,不过不是杀没用的,而是杀有用的。
就是有时候想一边听歌一边上网,当时只要一个酷狗和一个uc开着就行了,可是老是自动把我的酷狗给关了,然后动手开了,过不了一会儿又自动给关了,一个手机不可能两个程序都开不了,就是这个内存管理机制还不够智能,老保留着没用的,杀有用的,真是气死人了。有时候用那些手机卫士去杀进程,过不了多久那些进程又有了。直接重启!和苹果对比,说真的,苹果手机我不是很喜欢,第一,太贵,第二,在下载软件、刷机方面不够自由。综合这两条,也就是自己动手可玩性不高。
但是不得不承认,在运行方面苹果真的很流畅,就算用了几年,和新买时运行的速度差别都不大。安卓的用个一年就卡掉牙了。
B. 内存要怎样管理与维护
管理一、 进程的虚拟地址空间
每个进程都被赋予自己的虚拟地址空间,对于32位进程来说,这个地址空间为4G,因此进程中的地址可以为0X00000000至0XFFFFFFFF之间的任何一个值。其中4G空间中的低区的2G空间留给进程使用,而高区的2G空间则留给系统使用。
在Windows2000下,分区情况为:
1、 NULL指针分配的分区
NULL指针分配的分区占据0x00000000至0x0000FFFF,该分区的设置是为了帮助程序员掌握NULL指针的分配情况。例如当malloc或new分配失败时就返回NULL,该分区的地址是禁止进入的,访问该分区内的地址将发生访问违规现象,同时终止该进程的运行。
2、 用户方式分区
该分区是进程私有的地址空间,对于应用程序来讲,该分区是维护进程的大部分数据的地方,所有的.exe和dll模块均加载在这个分区,每个进程可以将dll加载到不同的地址中。对于.exe而言,一般加载到0x00400000地址处。
进程的栈和堆也是在该分区中开辟的。
3、 禁止进入分区
该分区是用户方式分区上禁止进入的分区,位于0x7FFF0000至0x7FFFFFFF,访问该分区的任何企图均将导致访问违规,该分区的存在是为了防止用户从用户区访问内核区的代码。如:
BYTE buf[70000];
DWORD numWritten;
WriteProcessMemory(GetCurrentProces(), (PVOID)0x7FFEEE90, buf, sizeof(buf), &numWritten);
将有可能成功地将数据写入只能有内核方式代码访问的内存。
4、 内核方式分区
该分区是存放操作系统代码的地方,用于线程调度、内存管理、文件系统支持、网络支持和所有设备驱动程序的代码全部在这个分区加载驻留在该分区的一切均可被所有近进程共享。
二、 虚拟内存的实现
本质上虚拟内存就是要让一个程序的代码和数据再没有全部载入内存的情况下运行程序。运行过程中,当执行到尚未载入的内存代码,或者要访问还没有载入到内存的数据时,虚拟内存管理器动态的将这部分代码或数据从硬盘载入到内存中。而且在通常情况下,虚拟内存管理器也会相应的将内存中某些代码或者数据置换到硬盘中,为即将载入的代码或数据腾出地方。
Win32中用来辅助实现虚拟内存的硬盘文件称为“调页文件”,调页文件用来存放被虚拟内存管理器置换处内存的数据,当这些数据再次被进程访问时,虚拟内存管理器会先将它们从调页文件中置换进内存,这样进程可以正确访问这些数据。
程序代码(包括exe和dll文件)不会被修改,所以他们所在的页被置换处内存时,并不会被写进调页文件中,而是直接抛弃,当再次被需要时,虚拟内存管理器直接从存放他们的exe或dll文件中找到他们并调入内存。
三、 虚拟内存的状态
近处虚拟地址空间中的页有三种状态:自由(free)、预留(reserved)和提交(committed)。
1、自由
自由表示此页尚未分配出去,可以用来满足新的内存分配请求。
2、预留
预留是指从虚拟地址空间中划出一块区域(页的整数倍大小),划出之后的区域中的页不能用来满足新的内存分配请求,只是用来供要求“预留”此段区域的代码以后使用,预留状态的区域并没有分配物理存储,只是增加了一个描述进程虚拟地址空姐使用状态的数据结构,用来记录这块区域已倍预留。
3、提交
提交内存时会从调页文件中开辟空间,并修改VAD中的相应项。当然,此时并没有立刻从物理内存中分配空间,只是从磁盘的调页文件中开辟空间。
当有代码第一次访问这段提交内存中的某些数据时,系统发现并没有真正的物理内存,抛出缺页异常,虚拟内存管理器处理该异常,此时才会真正的分配物理内存。
四、 虚拟内存状态的管理
Win32虚拟内存管理器使用一个数据结构(Virtual Address Descriptor, VAD)来记录和维护每个进程4G的虚拟地址空姐的使用及状态,美国进程都有自己的VAD集合,这个集合被组织成一个自平衡二叉树。只有预留或提交的内存块才有VAD,自由的内存块没有VAD,因此不在VAD数据结构中的虚拟地址就是自由的。每块VAD数据结构记录了该块的起始地址以及当前状态。
五、 访问虚拟内存时的处理流程
对某虚拟内存区域进行了预留并提交之后,就可以对该区域中的数据进行访问了,一下为访问虚拟内存时的处理流程。
1、当被访问数据已在物理内存时,虚拟内存管理器只需记那个该数据的虚拟地址映射为物理指针。
2、当被访问的数据不在物理内存时,检测此数据是否在调页文件中或者在exe或dll文件中,若存在则进入下一步,否则发生访问违例错误,进程退出。
3、判断内存中是否有空闲页,若存在空闲页,则直接将调页文件或exe或dll文件的数据加载到该空闲页中。
虚拟内存管理器维护了一个称为“页帧数据库page-frame database”的数据结构,该数据结构时操作系统全局的,当系统启动时被初始化,用来跟踪和记录物理内存真能干的每个页的状态。
4、当内存中不存在空闲页时,根据调页算法,首先选择出某个页作为换出页。
5、判断此页自上次调进后是否修改过,若没有被修改过,则将需要访问的数据调入此页,若被修改过,则需要先将此页的内容写到调页文件与此页相对应的备份页中,并随即将此页标记为空闲页。
六、 虚拟地址到物理地址的映射
当访问的数据已在物理内存中后,需要将虚拟地址转换为物理地址,即“地址映射”,才能真正访问此数据。
每个进程都维护一套自己的层次表结构来实现地址映射。
第一层称为“目录表”,实际上是一个内存页,以四个字节为单元分成1024个项,每一项称为“页目录项”。
第二层称为“页表”,共有1024个页表,页目录表中的每个目录表项对应这一层中的某个页表,每个页表也占一个内存也,同样被分成1024项,表页的每一项称为“页表项”,每个页表项指向物理内存中的某一个页帧。
第三层称为页帧,是真正存数数据的地方。
当进行地址映射的时候,对应于层次表中的三个部分,页将32位的地址分成三个部分,最高的十位对应页目录下标,次高的十位对应页表的下标,低位的12位对应字节下标作为页内寻址。
维护最好别让进程占用内存大和长时间,没用的进程尽快关,保持系统的顺利;用优化大师优化内存,定时检查内存有无病毒。硬件维护方面就要看看内存槽有没有积尘灰,有的话要清理,清理时候也要注意一下别伤到内存槽和内存。
C. 内存管理机制
一内存管理机制概述
从操作系统的角度来说,内存就是一块数据存储区域,而且他是可以被操作系统调动的资源。在现在的多进程操作系统当中,内存管理十分重要。操作系统它会为每一个进程合理分配内存资源,这里我们来从两个角度来分析,什么是内存管理机制。
1、分配机制
操作系统它会为每一个进程分配一个合理的大小,从而他能保证每一个进程能够正常的运行。而不至于内存不够使用或者某个进程占用太多的内存,这就是操作系统里面的分配概念。
2、回收机制(这一块是操作系统特别重要的一块)
在系统内存不足的时候,他会有一个回收再分配内存资源的机制,从而能够保证新的进程能够正常运行。而回收的时候就要杀死那些占有内存的进程,所以操作系统需要提供一套合理的杀死这些进程的机制,从而把副作用将到最低,而对于我们安卓系统来说,它对内存管理也有一套特别的办法,它和PC端是不一样的。我们都知道安卓它是移动操作系统,一般情况下安卓的内存资源会比PC端更少,所以我们就要更加谨慎的管理内存。
二 Android 内存管理机制
1、分配机制
我们知道,安卓在为每一个进程分配内存的时候,它采用了一个弹性的分配方式,比如刚开始他不会为一个新的APP分配太多的内存空间,而是给每一个app进程分配一个小额的内存量,而这个量是根据每一个移动端设备物理尺寸大小所决定,随着你的APP不断的运行,你可能发现当前内存已经不够使用了,这个时候安卓就会为每一个进程分配额外的大小,但是我们需要注意的是,分配的额外的内存大小不是随意去分配的,他是有限度的。因为我们都知道,安卓的内存大小是有限制的,所以说系统不可能为每一个APP进程分配无限大的内存.
总结:安卓的分配机制它的最大限度就是让更多的进程存活在内存当中,当用户下次再次启动时,他就不需要重新创建进程,他只需要恢复已有的进程即可,这样就减少了应用启动的时候,提高用户体验。
2、回收机制
安卓对内存的使用,他的宗旨是尽最大限度的使用。它是继承linux的特点,安卓系统他会在内存中保存尽可能多的数据。这里也有一个缺点,比如说有的进程不再被使用,但是数据还保存在内存当中,所以现在安卓不推荐直接退出应用。如果这样当用户下次启动应用的时候,只需要恢复当前进程即可,而不需要创建新进程。当安卓发现内存不够使用,开始回收内存的时候,安卓就会杀死其他进程。来回收足够的内存,从而开启新的进程。这里注意,对于进程分配他有一个优先级的概念,
优先级它主要分为五个阶段。
第一:前台进程,屏幕当中显示的进程
第二:可见进程,他已经不属于前台进程,用户仍能看见的进程,
第三:服务进程,例如定位、闹钟等。
第四:后台进程,后台进程不同于服务进程,它是在后台处理一些计算的进程.
第五:空进程,没有任何东西在内存运行的进程。内存可以随时回收。
三、安卓中为什么会有这五个分级
答:因为优先级越低的进程,被内存回收的概率越大
1、例如前台进程、可见进程、服务进程:一般情况下是不会被杀死的,
2、后台进程:他会存放在一个缓存的列表中,就是lru(最进最少使用的)缓存机制,先杀死的进程他会处于这个列表的尾部(也就是最进最少使用的后台进程会被第一个杀死)。
3、空进程:他是为了平衡整个系统的性能,安卓是不会保存这些进程的,
四、回收效率概念是什么
答:当安卓开始杀死进程的时候,系统会判断每一个杀死后所带来的回收效益,因为安卓更喜欢杀死一个能够回收更多内存的进程,在这里我们就知道,可以杀死更多的进程,来获取更多的内存。当然我们还是希望能够杀死少的进程,这样对用户的体验影响越小。
五、遵循内存管理机制的目标
答:我们在开发项目的时候,都会给APP顶订一个内存目标,这目标有以下几点:
1、更少的占用内存:我们都知道,如果一个APP性能更好,站用户手机的内存越少,这样对用户的体验,都是一个很好的目标。
2、在合适的时候,合理的释放系统资源。(并不是你不要的马上就要回收,如果频繁的释放对象,会造成内存抖动,而内存抖动会造成很多不好的现象,比如UI卡顿、anr、甚至是oom)
3、在系统内存紧张的时候,能释放掉大部分不重要的资源,来为Android系统提供可用的内存。
4、能够很合理的在特殊生命周期中,保存或者还原重要数据,以至于系统能够正确的重新回复应用
六、内存优化方法。
答:我们在开发项目的时候,都会给APP顶订一个内存目标,这目标有以下几点:
1、当service完成任务,尽量停止它。我们知道service进程优先级是比较低的,他的优先级叫做服务进程。所以这会影响到它的内存回收,这里我们可以用IntentService替换Service完成所需要的任务。
好处有两点:
第一点:我们知道IntentService是继承Service,他也是一个服务,但是他不同Service的地方,Service是默认在主线程,所以Service不可以做耗时操作, 是内部开启一个子线程,所以在他的onHandleIntent方法中,可以做一些耗时操作。
第二点:IntentService执行完之后他会自动停止,而Service必须手动调用才能停止,如果Service没有退出就会造成内存的泄露。
2、在UI不可见的时候,释放掉一些只有UI使用的资源
3、在系统内存紧张的时候,尽可能多的释放掉一些非重要的资源。
4、避免滥用Bitmap导致资源浪费。(根据当前分辨率压缩Bitmap是最好的选择,只用后要调用recycle方法释放掉Bitmap在C内存中的内存,也可以使用软引用引用一个Bitmap,然后使用lru缓存,来对Bitmap进行缓存算法)
5、使用针对内存优化过的数据容器,少用枚举常量,它消耗的内存是普通常量的两倍多
6、避免使用依赖注入框架。:例如我们项目开发过程中,会使用很多的注入框架,例如ButterKnife。使用这些依赖框架有好的地方,但是也会给我们带来额外的服务。
7、使用多进程,例如定位、推送、WebView就可以写一个后台进程来执行。特别是Webview如果不开启一个进程的话就会造成内存泄露。