当前位置:首页 > android内存管理机制分析
Android系统内存管理机制分析
一、Android和 Android 内存管理基本介绍
Android 内核是基于Linux 2.6内核的(目前最新开发版本是2.6.31),它是一个强内核
版本,除了修改部分 Bug 外,它提供了用于支持 Android 平台的设备驱动,其核心驱动主要包括:
Android Binder ,基于OpenBinder框架的一个驱动,用于提供Android平台的进间通讯(IPC,inter-process communication)。 源代码位于drivers/staging/Android/binder.c
Android 电源管理(PM) ,一个基于标准Linux电源管理系统的轻量级的Android源管理驱动,针对嵌入式设备做了很多优化。源代码位于kernel/power/earlysuspend. kernel/power/consoleearlysuspend.c kernel/power/fbearlysuspend.c kernel/power/wakelock.c kernel/power/userwakelock.c
低内存管理器(Low Memory Killer) ,相对于Linux标准 OOM(Out Of Memory机制更加灵活,它可以根据需要杀死进程来释放需要的内存。 源代码位于drivers/staging/Android/lowmemorykiller.c
匿名共享内存(ashmem) ,为进程间提供大块共享内存,同时为内核提供回收和理这个内存的机制。源代码位于mm/ashmem.c
Android PMEM(Physical) ,PMEM 用于向用户空间提供连续的物理内存区域,D和某些设备只能工作在连续的物理内存上。源代码位于drivers/misc/pmem.c
Android Logger ,一个轻量级的日志设备,用于抓取Android 系统的各种日志。 代码位于drivers/staging/Android/logger.c
Android Alarm ,提供了一个定时器用于把设备从睡眠状态唤醒,同时它也提供了个即使在设备睡眠时也会运行的时钟基准,源代码位于drivers/rtc/alarm.c
USB Gadget 驱动 ,一个基于标准Linux USB gadget 驱动框架的设备驱动,Andro的USB驱动是基于gaeget框架的,源代码位于drivers/usb/gadget/
Android Ram Console ,为了提供调试功能,Android允许将调试日志信息写入一被称为RAM Console的设备里,它是一个基于RAM的Buffer。源代码位于drivers/staging/Android/ram_console.c。
每个Android应用都运行在一个单独的进程在它自己的Dalvik的实例,负责所有的Android运行时的内存和进程管理的责任,停止和死亡过程的必要的管理资源。 Dalvik 和Android运行时间在一个Linux内核,处理低层次的硬件交互,包括驱动程序和内存管理,其API提供下层的服务,功能,和硬件的访问。
Dalvik虚拟机是基于寄存器的虚拟机的优化,以确保设备可以有效地运行多个实例。 它依赖于Linux内核线程和低级的内存管理。
二、Android的内存机制和溢出说明
Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M。但是Android采用的是Java语言编写,所在很大程度上,Android的内存机制等同于Java的内存机制(Java内存机制在网上帖子很多,大家有兴趣了解的可以去谷歌或者百度查找一些资料)。因此在一些程序员开发的时候,内存的限制问题给很多初学开发者带来内存溢出等严重问题。在我们不使用一些内存的时候,我们要尽量在Android或者其他平台上避免在运行其他程序时,保存必要的状态,使得一些死进程所带来的内存问题,应该尽量在关闭程序或者保存状态的时候释放掉。这样能提高系统在运行方面的流畅性。 Android的内存主要表现在:
1. 在Android平台上,长期保持一些资源的引用,造成一些内存不能释放,带来的内
存泄露问题很多。比如:Context(下文中提到的Activity都是Context),在一些你需要保持你的首个类对象状态,并且把状态传入其他类对象中时,这样消除掉首个类对象之前,你必须先把接收类对象释放掉。需要注意一点的是:因为在Java或者Android内存机制中,顶点的结点释放前必须保证其他对象没有调用才能被系统GC回收释放。我们看一段代码:
@Override
protected void onCreate(Bundle state) { super.onCreate(state);
TextView label = new TextView(this); label.setText(\ setContentView(label); }
这个代码的意思就是我们把一个TextView的实例加载到了我们正在运行的
Activity(Context)当中,因此,通过GC回收机制,我们知道,要释放Context,就必须先释放掉引用他的一些对象。如果没有,那在要释放Context的时候,你会发现会有大量的内存溢出。所以在你不小心的情况下内存溢出是一件非常容易的事情。
2. 保存一些对象时,同时也会造成内存泄露。最简单的比如说位图(Bitmap),比如
说:在屏幕旋转时,会破坏当前保持的一个Activity状态,并且重新申请生成新的Activity,直到新的Activity状态被保存。我们再看一段代码:
private static Drawable sBackground; @Override
protected void onCreate(Bundle state) { super.onCreate(state);
TextView label = new TextView(this); label.setText(\
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap); }
label.setBackgroundDrawable(sBackground); setContentView(label); }
这个代码是非常快的同时也是错误的。它的内存泄露很容易出在屏幕转移的方向上。虽然我们会发现没有显示的保存Context这个实例,但是当我们把绘制的图连接到一个视图的时候,Drawable就会将被View设置为回调,这就说明,在上述的代码中,其实在绘制TextView到活动中的时候,我们已经引用到了这个Activity。链接情况可以表现为:Drawable->TextView->Context。
所以在想要释放Context的时候,其实还是保存在内存中,并没有得到释放。
如何避免这种情况:主要在于。线程最容易出错。大家不要小看线程,在Android里面线程最容易造成内存泄露。线程产生内存泄露的主要原因在于线程生命周期的不可控。下面有一段代码:
public class MyTest extends Activity { @Override
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new MyThread().start(); }
private class MyThread extends Thread{ @Override
public void run() { super.run(); //do somthing } } }
代码很简单,但是在Android上又来新问题了,当我们在切换视图屏幕的时候(横竖屏),就会重新建立横屏或者竖屏的Activity。我们形象的认为之前建立的Activity会被回收,但是事实如何呢?Java机制不会给你同样的感受,在我们释放Activity之前,因为run函数没有结束,这样MyThread并没有销毁,因此引用它的Activity(Mytest)也有没有被销毁,因此也带来的内存泄露问题。
有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。 线程问题的改进方式主要有:
? 将线程的内部类,改为静态内部类。 ? 在程序中尽量采用弱引用保存Context。 3. 万恶的bitmap。。。
Bitmap是一个很万恶的对象,对于一个内存对象,如果该对象所占内存过大,在超出了系统的内存限制时候,内存泄露问题就很明显了。。
解决bitmap主要是要解决在内存尽量不保存它或者使得采样率变小。在很多场合下,因为我们的图片像素很高,而对于手机屏幕尺寸来说我们并不用那么高像素比例的图片来加载时,我们就可以先把图片的采样率降低在做原来的UI操作。
如果在我们不需要保存bitmap对象的引用时候,我们还可以用软引用来做替换。具体的实例代码google上面也有很多。
三、有效使用内存
Android 的管理打开的应用程序是在后台运行,所以你不应该关闭这个。同时这意味着,关闭应用程序时,系统需要更多的内存。 然而,大多数Android 用户不是很满意,它的东
西它是如何,因为有时留下太多的进程运行,从而导致在日常生活中表现呆滞。 我们可以利用先进的任务杀手/任务管理器和它的工作非常好。
合理使用内存,正确认识任务管理器 Android内存原理不用在意剩余内存的大小。其实很多人都是把使用其他系统的习惯带过来来了,安卓Android大多应用没有退出的设计其实是有道理的,这和系统对进程的调度机制有关系。如果你知道java,就能更清楚这机制了。其实和java的垃圾回收机制类似,系统有一个规则来回收内存.进行内存调度有个阀值,只有低于这个值系统才会按一个列表来关闭用户不需要的东西。当然这个值默认设置得很小,所以你会看到内存老在很少的数值徘徊.但事实上他并不影响速度。相反加快了下次启动应用的速度。这本来就是安卓Android标榜的优势之一,如果人为去关闭进程,没有太大必要.特别是自动关进程的软件。
那么,进程管理软件有无必要呢?有的。就是在运行大型程序之前,你可以手动关闭一些进程释放内存,可以显著的提高运行速度。但一些小程序,完全可交由系统自己管理。谈到这里,可能有的朋友会问,如果不关程序是不是会更耗电。我就说说安卓Android后台的原理,你就明白了。安卓Android的应用在被切换到后台时,它其实已经被暂停了,并不会消耗cpu资源,只保留了运行状态。所以为什么有的程序切出去重进会到主界面。但是,一个程序如果想要在后台处理些东西,如音乐播放,它就会开启一个服务,服务可在后台持续运行,所以在后台耗电的也只有带服务的应用了。这个在进程管理软件里能看到,标签是service。至于广播什么的我就不涉及了,所以没有带服务的应用在后台是完全不耗电的,没有必要关闭。这种设计本来就是一个非常好的设计,下次启动程序时,会更快,因为不需要读取界面资源,何必要关掉他们抹杀这个安卓Android的优点呢?
还有一个,为什么安卓Android一个应用看起来那么耗内存?大家知道,安卓Android上的应用是java,当然需要虚拟机,而安卓Android上的应用是带有独立虚拟机的,也就是每开一个应用就会打开一个独立的虚拟机。这样设计的原因是可以避免虚拟机崩溃导致整个系统崩溃,但代价就是需要更多内存。
以上这些设计确保了安卓Android的稳定性。正常情况下最多单个程序崩溃,但整个系统不会崩溃,也永远没有内存不足的提示出现。大家可能是被windows毒害得太深了,总想保留更多的内存。但实际上这并不一定会提升速度,相反却丧失了程序启动快的这一系统特色,很没必要。大家不妨按我说的习惯来用用这个系统。最后推荐一款进程管理软件:systempanel,market上能搜到,界面友好启动快,功能也不错,用于手动关闭进程很好的软件, 祝大家玩机愉快。这系统开十天半个月都没问题,不是windows。
共分享92篇相关文档