平板左下角出现使命召唤11low memoryy然后弹出来

Android乱弹onLowMemory()和onTrimMemory() - 综合技术 - 程序员人生-专注互联网开发
Android乱弹onLowMemory()和onTrimMemory()
发布时间: | 阅读次数:次 | 分类:
程序员手册:一套好的人机操作界面要求,对于新手,能够一步一步的引导他进入功能,相反对于熟客,能够直奔主题;妓女同样要遵守程序员手册对人鸡界面的规定Android在内存管理上与linux有些小的区别。其中一个就是引入了Low memory killer .
1,引入原因
& &Android是一个多任务系统,也就是说可以同时运行多个程序,这个大家应该很熟悉。一般来说,启动运行一个程序是有一定的时间开销的,因此为了加快运行速度,当你退出一个程序时,Android并不会立即杀掉它,这样下次再运行该程序时,可以很快的启动。随着系统中保留的程序越来越多,内存肯定会出现不足,low memory killer就是在系统内存低于某值时,清除相关的程序,保障系统保持拥有一定数量的空闲内存。
& &Android中,进程的生命周期都是由系统控制的,即使用户关掉了程序,进程依然是存在于内存之中。这样设计的目的是为了下次能快速启动。当然,随着系统运行时间的增长,内存会越来越少。Android Kernel 会定时执行一次检查,杀死一些进程,释放掉内存。
& & 那么,如何来判断,那些进程是需要杀死的呢?答案就是我们的标题:Low memory killer机制。
& & Android 的Low memory killer是基于linux的OOM(out of memory) &规则改进而来的。 OOM通过一些比较复杂的评分机制,对进程进行打分,然后将分数高的进程判定为bad进程,杀死并释放内存。OOM只有当系统内存不足的时候才会启动检查,而Low memory killer 则是定时进行检查。
& & &Low memory killer 主要是通过进程的oom_adj 来判定进程的重要程度。oom_adj的大小和进程的类型以及进程被调度的次序有关。
& & &Low memory killer 的具体实现可参看:kernel/drivers/misc/lowmemorykiller.c&
& & &其原理很简单,在linux中,存在一个kswapd的内核线程,当linux回收存放分页的时候,kswapd线程将会遍历一张shrinker链表,并执行回调,定义如下:
struct shrinker{
int (*shrink)(int nr_to_scan, gfp_t gfp_mask);
struct list_
#define DEFAULT_SEEKS 2
extern void register_shrinker(struct shrinker *);
extern void unregiter_shrinker(struct shrinker *);
所以只要注册 Shrinker,变可以在内存分页回收时根据规则释放内存,下面我们来看看其实现。&
首先定义shrinker结构体,lowmem_shrink为回调函数的指针,当有内存分页回收的时候,这个函数将会被调用。
static struct shrinker lowmem_shrinker = {
   .shrink = lowmem_shrink,
   .seeks = DEFAULT_SEEKS * 16
2. 基本原理和重要概念
& &Low memory killer根据两个原则,进程的重要性和释放这个进程可获取的空闲内存数量,来决定释放的进程。
(1)进程的重要性,由task_struct-&signal_struct-&oom_adj决定。
Android将程序分成以下几类,按照重要性依次降低的顺序:
名称 oom_adj 解释&
FOREGROUD_APP 0 前台程序,可以理解为你正在使用的程序&
VISIBLE_APP 1 用户可见的程序&
SECONDARY_SERVER 2 后台服务,比如说QQ会在后台运行服务&
HOME_APP 4 HOME,就是主界面&
HIDDEN_APP 7 被隐藏的程序&
CONTENT_PROVIDER 14 内容提供者,&
EMPTY_APP&15 &空程序,既不提供服务,也不提供内容
其中每个程序都会有一个oom_adj值,这个值越小,程序越重要,被杀的可能性越低。
(2)进程的内存,通过get_mm_rss获取,在相同的oom_adj下,内存大的,优先被杀。
(3)那内存低到什么情况下,low memory killer开始干活呢?Android提供了两个数组,一个lowmem_adj,一个lowmem_minfree。前者存放着oom_adj的阀值,后者存放着minfree的警戒值,以page为单位(4K)。
oom_adj 内存警戒值( 以4K为单位)
3.源码解析
module_init(lowmem_init);
&module_exit(lowmem_exit);
& & 模块加载和退出的函数,主要的功能就是register_shrinker和unregister_shrinker结构体lowmem_shrinker。主要是将函数lowmem_shrink注册到shrinker链表里,在mm_scan调用。
下面详细的介绍这个函数:
&for (i = 0; i & array_ i++) {
& & & & if (other_file & lowmem_minfree[i]) {
& & & & & & min_adj = lowmem_adj[i];
& & & & & &
other_file,系统的空闲内存数,根据上面的逻辑判断出,low memory killer需要对adj高于多少(min_adj)的进程进行分析是否释放。
& if (nr_to_scan &= 0 || min_adj == OOM_ADJUST_MAX + 1) {
& & & & lowmem_print(5, &lowmem_shrink %d, %x, return %d\n&,
& & & & & & & & &nr_to_scan, gfp_mask, rem);
& 判断,系统当前的状态是否需要进行low memory killer。
for_each_process(p) {
& & & & struct mm_struct *
& & & & struct signal_struct *
& & & & int oom_
& & & & task_lock(p);
& & & & mm = p-&
& & & & sig = p-&
& & & & if (!mm || !sig) {
& & & & & & task_unlock(p);
& & & & & &
& & & & oom_adj = sig-&oom_
& & & & if (oom_adj & min_adj) {
& & & & & & task_unlock(p);
& & & & & &
& & & & tasksize = get_mm_rss(mm);
& & & & task_unlock(p);
& & & & if (tasksize &= 0)
& & & & & &
& & & & if (selected) {
& & & & & & if (oom_adj & selected_oom_adj)
& & & & & & & &
& & & & & & if (oom_adj == selected_oom_adj &&
& & & & & & & & tasksize &= selected_tasksize)
& & & & & & & &
& & & & selected =
& & & & selected_tasksize =
& & & & selected_oom_adj = oom_
& & & & lowmem_print(2, &select %d (%s), adj %d, size %d, to kill\n&,
& & & & & & & & &p-&pid, p-&comm, oom_adj, tasksize);
对每个sig-&oom_adj大于min_adj的进程,找到占用内存最大的进程存放在selected中。
if (selected) {
& & & & if (fatal_signal_pending(selected)) {
& & & & & & pr_warning(&process %d is suffering a slow death\n&,
& & & & & & & & & &selected-&pid);
& & & & & & read_unlock(&tasklist_lock);
& & & & & &
& & & & lowmem_print(1, &send sigkill to %d (%s), adj %d, size %d\n&,
& & & & & & & & &selected-&pid, selected-&comm,
& & & & & & & & &selected_oom_adj, selected_tasksize);
& & & & force_sig(SIGKILL, selected);
& & & & rem -= selected_
&发送SIGKILL信息,杀掉该进程。
关于Low Memory Killer的分析就到这里,在了解了其机制和原理之后,我们发现它的实现非常简单,与标准的Linux OOM机制类似,只是实现方式稍有不同。标准Linux的OOM Killer机制在mm/oom_kill.c中实现,且会被__alloc_pages_may_oom调用(在分配内存时,即mm/page_alloc.c中)。oom_kill.c最主要的一个函数是out_of_memory,它选择一个bad进程Kill,Kill的方法同样是通过发送SIGKILL信号。在out_of_memory中通过调用select_bad_process来选择一个进程Kill,选择的依据在badness函数中实现,基于多个标准来给每个进程评分,评分最高的被选中并Kill。一般而言,占用内存越多,oom_adj就越大,也就越有可能被选中。
4. 资源配置
阈值表可以通过/sys/module/lowmemorykiller/parameters/adj和/sys/module/lowmemorykiller/parameters/minfree进行配置,例如在init.rc中:
# Write value must be consistent with the above properties.
& &write&/sys/module/lowmemorykiller/parameters/adj&0,1,2,7,14,15
& &write /proc/sys/vm/overcommit_memory 1
& &write&/sys/module/lowmemorykiller/parameters/minfree96,44
& &class_start default
进程oom_adj同样可以进行设置,通过write /proc/&PID&/oom_adj &,在init.rc中,init进程的pid为1,omm_adj被配置为-16,永远不会被杀死。
& &# Set init its forked children's oom_adj.
& &write /proc/1/oom_adj -16
& &Low memory killer的基本原理我们应该弄清了,正如我前面所说的,进程omm_adj的大小跟进程的类型以及进程被调度的次序有关。进程的类型,可以在ActivityManagerService中清楚的看到:&
& & static final int EMPTY_APP_ADJ;
& & static final int HIDDEN_APP_MAX_ADJ;
& & static final int HIDDEN_APP_MIN_ADJ;
& & static final int HOME_APP_ADJ;
& & static final int BACKUP_APP_ADJ;
& & static final int SECONDARY_SERVER_ADJ;
& & static final int HEAVY_WEIGHT_APP_ADJ;
& & static final int PERCEPTIBLE_APP_ADJ;
& & static final int VISIBLE_APP_ADJ;
& & static final int FOREGROUND_APP_ADJ;
& & static final int CORE_SERVER_ADJ = -12;
& & static final int SYSTEM_ADJ = -16;&
& &ActivityManagerService定义各种进程的oom_adj,CORE_SERVER_ADJ代表一些核心的服务的omm_adj,数值为-12,由前面的分析可知道,这类进程永远也不会被杀死。
其他未赋值的都在static块中进行了初始化,是通过system/rootdir/init.rc进行配置的:
&在init.rc中:
# Define the oom_adj values for the classes of processes that can be
# killed by the kernel. &These are used in ActivityManagerService.
& &setprop ro.FOREGROUND_APP_ADJ 0
& &setprop ro.VISIBLE_APP_ADJ 1
& &setprop ro.SECONDARY_SERVER_ADJ 2
& &setprop ro.HIDDEN_APP_MIN_ADJ 7
& &setprop ro.CONTENT_PROVIDER_ADJ 14
& &setprop ro.EMPTY_APP_ADJ 15
# Define the memory thresholds at which the above process classes will
# be killed. &These numbers are in pages (4k).
& &setprop ro.FOREGROUND_APP_MEM 1536
& &setprop ro.VISIBLE_APP_MEM 2048
& &setprop ro.SECONDARY_SERVER_MEM 4096
& &setprop ro.HIDDEN_APP_MEM 5120
& &setprop ro.CONTENT_PROVIDER_MEM 5632
& &setprop ro.EMPTY_APP_MEM 6144
& 由此我们知道EMPTY_APP 最容易被杀死,其实是CONTENT_PROVIDER ,FOREGROUND的进程很难被杀死。
& 现在我们再来说影响oom_adj的第二个因素,进程的调度次序。这涉及到了ActivityManagerService的复杂调度,我们下次再来看吧。
Android将进程分为6个等级,它们按优先级顺序由高到低依次是:
& &&1. FOREGROUND_APP:
& & This is the process running the current foreground app. &We'd really rather not kill it!
& & 用户正在使用的程序. 这个设的太高,用户看到得就会是一个正在使用的程序莫名其妙的消失了,然后自动回到桌面..(因为它被系统kill了..) 所以最好别动它.
& & 2. VISIBLE_APP:
& & This is a process only hosting activities that are visible to the user, so we'd prefer they don't disappear.
& & 跟FOREGROUND_APP类似,用户正在使用/看得到. 它们的区别就是VISIBLE_APP可能不是用户focus的程序,但是用户看得到,或者没有覆盖到整个屏幕,只有屏幕的一部分. 所以可以适当的比FOREGROUND_APP高一点.
& & 3. SECONDARY_SERVER:
& & This is a process holding a secondary server -- killing it will not have much of an impact as far as the user is concerned.
& & 所有应用的service. 系统级的service比如PhoneService不属于这类,它们是绝不会被Android结束掉的. 所以这个可以适当的设高一点点~ 注意, HOME(SenseUI)也包括在这里 因此还是别设的太高. 要不每次返回桌面都得等它重新load,特别是widget多的.
& & 4. HIDDEN_APP:
& & This is a process only hosting activities that are not visible, so it can be killed without any disruption.
& & 本来属于1或者2的程序, 在用户按了&back&或者&home&后,程序本身看不到了,但是其实还在运行的程序,它们就属于HIDDEN_APP了. 干掉没什么影响.. 不过要了解并不是所有属于这一类的就应该马上结束掉,像push mail,locale,闹钟,等都属于这一类. 因此还是别设的过高. 真正&应该&一点返回键就退出的程序(真正没用的程序)在下面.
& & 5. CONTENT_PROVIDER:
& & This is a process with a content provider that does not have any clients attached to it. &If it did have any clients, its adjustment would be the one for the highest-priority of those processes.
& & 5,6的区别具体不太了解..这个也是用处不大,但是还是比EMPTY_APP稍微有点用.. 所以高点没关系~,&
& & 6. EMPTY_APP:
& & This is a process without anything currently running in it. &Definitely the first to go! This value is initalized in the constructor, careful when refering to this static variable externally.
& & 完全没用的一个,杀了它只有好处没坏处,第一个干它!
The configuration is set in the file: &/sys/module/lowmemorykiller/parameters/minfree&&
查看现在的设置可以:
& &1. #&cat /sys/module/lowmemorykiller/parameters/minfree
显示出的应该是6个数字,以逗号隔开,例如:
注意这些数字的单位是page. 1 page = 4 kilobyte.
上面的六个数字对应的就是(MB): 6,8,16,20,22,24
这些数字也就是对应的内存阀值,一旦低于该值,Android便开始按顺序关闭进程. 因此Android开始结束优先级最低的EMPTY_APP当可用内存小于24MB(4).
有一点没搞明白,它的可用内存不知道是从哪得到.. 明显不是free显示的可用内存,而且貌似compcache跟swap也不影响.
要想重新设置该值:
& &1. # echo &96,,23040& & /sys/module/lowmemorykiller/parameters/
这样当可用内存低于90MB的时候便开始结束EMPTY_APP. 而当可用内存低于60MB的时候才开始结束CONTENT_PROVIDER组. 其余四个没动.
通过以上方法改变的数值并非永久.在下次重启后就又恢复到之前的设置. 若想让设置在每次开机执行,将;
& &echo &96,,25000& & /sys/module/lowmemorykiller/parameters/minfree
加入到任意一个开机启动的配置文件. 一般在/system/init.d下的文件都是开机执行的(有的ROM也可能不在这里..) 只需用记事本打开任意一个文件,再把这行加入其中就好.
个人经验补充一点:
一般前三个不用动,或者只是稍微改高一点就好,毕竟它们比较重要,不要太早结束. 值得关注的是后三个. 它们也可以适当的设大一点. 当然,任何东西都有一个度,像上面例子中EMPTY_APP搞到25000(97MB)并不至于大到离谱,hero我没有过 我在Magic 32A甚至还试过120MB..不过120MB那是有点过头了..游戏玩着玩着就消失回到桌面了(可用内存低于120MB被系统结束任务了).. 因此还是不要太高.
我目前的设置(开了32MB的CC加32MB的backing swap @60 swappiness):
& & 96,,19200
也许大家还不明白这样做的好处. 这样的好处就是让我们随时有足够的内存来执行我们要运行的程序,而那些真正没用的进程又不会多余的占用着宝贵的内存. 更重要的是这一切都是不需要您的参与或任何第三方软件的协助,完全由Android在后台自动执行. 试想,又有谁会比Android更熟悉的掌握每个进程呢 比起那些内存管理程序傻傻的一锅端的方法聪明多了吧~ 让我们从现在开始把那些内存管理程序删掉吧。
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
安卓Android的内存管理原理解析
Android采取了一种有别于Linux的进程管理策略,有别于Linux的在进程活动停止后就结束该进程,Android把这些进程都保留在内存中,直到系统需要更多内存为止。这些保留在内存中的进程通常情况下不会影响整体系统的运行速度,并且当用户再次激活这些进程时,提升了进程的启动速度。
那Android什么时候结束进程?结束哪个进程呢?之前普遍的认识是Android是依据一个名为LRU(last recently used 最近使用过的程序)列表,将程序进行排序,并结束最早的进程。
1.系统会对进程的重要性进行评估,并将重要性以“oom_adj”这个数值表示出来,赋予各个进程;(系统会根据“oom_adj”来判断需要结束哪些进程,一般来说,“oom_adj”的值越大,该进程被系统选中终止的可能就越高)
2.前台程序的“oom_adj”值为0,这意味着它不会被系统终止,一旦它不可访问后,会获得个更高的“oom_adj”,我们推测“oom_adj”的值是根据软件在LRU列表中的位置所决定的;
3.Android不同于Linux,有一套自己独特的进程管理模块,这个模块有更强的可定制性,可根据“oom_adj”值的范围来决定进程管理策略,比如可以设定“当内存小于X时,结束“oom_adj”大于Y的进程”。这给了进程管理脚本的编写以更多的选择。
前台进程(foreground):目前正在屏幕上显示的进程和一些系统进程。举例来说,Dialer Storage,Google Search等系统进程就是前台进程;再举例来说,当你运行一个程序,如浏览器,当浏览器界面在前台显示时,浏览器属于前台进程(foreground),但一旦你按home回到主界面,浏览器就变成了后台程序(background)。我们最不希望终止的进程就是前台进程。
可见进程(visible):可见进程是一些不再前台,但用户依然可见的进程,举个例来说:widget、输入法等,都属于visible。这部分进程虽然不在前台,但与我们的使用也密切相关,我们也不希望它们被终止(你肯定不希望时钟、天气,新闻等widget被终止,那它们将无法同步,你也不希望输入法被终止,否则你每次输入时都需要重新启动输入法)
次要服务(secondary server):目前正在运行的一些服务(主要服务,如拨号等,是不可能被进程管理终止的,故这里只谈次要服务),举例来说:谷歌企业套件,Gmail内部存储,联系人内部存储等。这部分服务虽然属于次要服务,但很一些系统功能依然息息相关,我们时常需要用到它们,所以也太希望他们被终止
.后台进程(hidden):虽然作者用了hidden这个词,但实际即是后台进程(background),就是我们通常意义上理解的启动后被切换到后台的进程,如浏览器,阅读器等。当程序显示在屏幕上时,他所运行的进程即为前台进程(foreground),一旦我们按home返回主界面(注意是按home,不是按back),程序就驻留在后台,成为后台进程(background)。后台进程的管理策略有多种:有较为积极的方式,一旦程序到达后台立即终止,这种方式会提高程序的运行速度,但无法加速程序的再次启动;也有较消极的方式,尽可能多的保留后台程序,虽然可能会影响到单个程序的运行速度,但在再次启动已启动的程序时,速度会有所提升。这里就需要用户根据自己的使用习惯找到一个平衡点
内容供应节点(content provider):没有程序实体,进提供内容供别的程序去用的,比如日历供应节点,邮件供应节点等。在终止进程时,这类程序应该有较高的优先权
空进程(empty):没有任何东西在内运行的进程,有些程序,比如BTE,在程序退出后,依然会在进程中驻留一个空进程,这个进程里没有任何数据在运行,作用往往是提高该程序下次的启动速度或者记录程序的一些历史信息。这部分进程无疑是应该最先终止的。
简单来说,就是选择退出程序时,并不是完全退出程序,该程序仍然会在后台驻留一个进程,以便下次更快的打开。那什么时候完全关闭该程序呢?这取决于该程序的类型(就是上面讲的那几个类型)。系统会给每个类型的程序一个内存值阈(阀门),也就是说当运行内存低于某个值时,系统会自动按照打开的先后顺序来关闭该类型的程序。例如,当运存小于24MB时,系统才会自动关闭空进程这一类型的程序,释放出更多的内存来供新程序使用,已保证新开程序的正常运行。
综上所述,我们不难看出,很多时候我们没必要过多的区关注系统的空闲内存(RAM)是多少,也没必要特意的去杀掉后台程序,因为系统会自动分配内存,以保证新程序的运行,特殊情况除外,比如你马上就要开一个非常大的游戏,需要更多的内存,这个时候就可以手动杀掉一些后台程序,以保证游戏的流畅。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:118604次
积分:1764
积分:1764
排名:第12117名
原创:41篇
转载:123篇
评论:12条
(5)(28)(15)(7)(5)(10)(3)(6)(7)(1)(1)(4)(9)(7)(3)(1)(3)(2)(8)(15)(1)(23)联想平板出现low memory关不了机,也开不了机,就是黑屏了_百度知道
联想平板出现low memory关不了机,也开不了机,就是黑屏了
尊敬的联想用户您好!你好,根据你描述的情况是内存过低导致开不了机或是黑屏。建议你关闭不常用的程序来释放内存。如果还会出现以上情况,建议您到就近的联想客户服务中心,由我们专业工程师帮您解决。联想服务网点查询期待您满意的评价,感谢您对联想的支持,祝您生活愉快!
已回答833349
响应时间&7小时
其他类似问题
为您推荐:
黑屏的相关知识
其他1条回答
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁Available Memory is low问题解决方法 -
- ITeye技术网站
博客分类:
在你安装的Eclipse目录下的eclipse.ini文件中添加。
以下是这些参数的意思:
vmargs:说明后面是VM的参数
-Xms40m:虚拟机占用系统的最小内存
-Xmx256m:虚拟机占用系统的最大内存
-XX:PermSize:最小堆大小。一般报内存不足时,都是说这个太小,
堆空间剩余小于5%就会警告,建议把这个稍微设
大一点,不过要视自己机器内存大小来设置
-XX:MaxPermSize:最大堆大小。这个也适当大些
-Xmx512M的5%为25.6M,理论上要求-Xmx的数值与-XX:MaxPermSize必须大于25.6M
配置事例:
-vmargs
-Xmx1024m
-XX:MaxPermSize=512m
-XX:ReservedCodeCacheSize=64m
lisongqiu168
浏览: 18226 次
来自: 上海}

我要回帖

更多关于 memory is low press 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信