android程序的内存管理与优化,Android 内存管理与优化

1.Android 内存基础

所有的内存都是基于物理内存的,即移动设备上的RAM。当启动一个Android程序时,会启动一个Dalvik vm 进程,系统会给它分配固定的内存空间,这块内存会映射到RAM上某个区域,然后Android程序就运行在这块空间上。JAVA里会将这块空间分成Stack栈内存和Heap堆内存。stack里存放对象的引用,heap里存放实际对象数据。

8db5cb0084f6

2.Android 问题与调节

Memory Leak(内存泄露):在程序中创建对象,不及时回收无效空间。

OutOfMemory(内存溢出):当应用程序申请的java heap空间超过Dalvik vm HeapGrowthLimit时,溢出。(内存溢出并不是内存不够,而是超过了Dalvik vm的限制)

Memory Churn(内存抖动):GC操作频繁,导致内存抖动。

调节:如果RAM申请的空间不足,那么Android的Memory Killer会杀死优先级低的进程。

3.Android默认内存回收机制——垃圾回收GC(Garbage Collection)

进程优先级:

Foreground:处于焦点的进程。

Visible:可以看见的进程。

Service:服务进程。

Background:后台进程。

Empty:空进程。

进行GC时刻:

app空闲的时候。

内存紧张的时候 。

分配大的内存块不够用的时候。

GC回收模型:

Generational Heap Memory

采用分代技术,分为年轻代、老年代、持久代。

8db5cb0084f6

最先清理的是年轻代,只要清理出足够的空间就不去清理老年代了。依次持久带也是这样。

GC回收步骤:

从GC Root开始,开始对对象引用遍历,找出GC Root直接引用的所有对象集1,再找出直接引用对象集1的对象集2……直到遍历完所有对象。这些对象都是有效对象。

删除其他无效对象。

注:GC执行的时候,当前所有线程的任何操作都会需要暂停。

4.优化——减少额外的内存使用

4.1 Bitmap

基本思路:缩略图,像素,图片回收,捕获OOM异常

缩略图:使用BitmapFactory.Options方法里的inSampleSize设置缩小比。

像素:

Android中图片有四种属性,分别是:

ALPHA_8:每个像素占用1byte内存

ARGB_4444:每个像素占用2byte内存

ARGB_8888:每个像素占用4byte内存 (默认)

RGB_565:每个像素占用2byte内存

默认是显示效果最好的ARGB_8888,可以使用BitmapFactory.Options的inPreferredConfig方法设置。

图片回收:

// 先判断是否已经回收

if(bitmap != null && !bitmap.isRecycled()){

// 回收并且置为null

bitmap.recycle();

bitmap = null;

}

System.gc();

捕获OOM异常:

Bitmap bitmap = null;

try {

// 实例化Bitmap

bitmap = BitmapFactory.decodeFile(path);

} catch (OutOfMemoryError e) {

// 捕获OutOfMemoryError,避免直接崩溃

}

if (bitmap == null) {

// 如果实例化失败 返回默认的Bitmap对象

return defaultBitmapMap;

}

4.2 软引用和弱引用

想避免OutOfMemory异常的发生,则可以使用软引用。

想要提高应用性能,尽快回收占用内存更大的对象,可以使用弱引用。

4.3 小Tips

Context的引用,具体请看这篇Android Context详解。

避免创建不必要的对象:你要频繁操作一个字符串时,使用StringBuffer代替String。

避免使用浮点数:在Android设备中,浮点数会比整型慢两倍。

循环:尽量避免在for的条件参数(即())中访问成员变量,调用方法,例如:

for(int i=0;i

for(int i=0;i

正确的做法如下:

int b = a.length/int b=a.length();

for(int i=0;i

java还有一种访问数组的方法,这种方法比普通循环多出4个字节,因为产生了一个额外的变量,如下列的a。

for(Foo a:Array){

m+=a.value;

}

了解并使用类库:

当你在处理字串的时候,不要吝惜使用String.indexOf(),String.lastIndexOf()等特殊实现的方法。这些方法都是使用C/C++实现的,比起Java循环快10到100倍。

android.text.format包下的Formatter类,提供了IP地址转换、文件大小转换等方法;DateFormat类,提供了各种时间转换,都是非常高效的方法。

TextUtils类,对于字符串处理Android为我们提供了一个简单实用的TextUtils类,如果处理比较简单的内容不用去思考正则表达式不妨试试这个在android.text.TextUtils的类。

5.优化—— 重复使用内存资源

将已经存在的内存资源重新使用而避免去创建新的。最典型的使用就是**缓存(Cache)和池(Pool)。

缓存:

一种是内存缓存,一种是硬盘缓存。

内存缓存(LruCache):存在宝贵的内存中。

硬盘缓存(DiskLruCache):存在硬盘中。

池:

一种是对象池,一种是线程池。

对象池:将用过的对象保存起来,等下一次使用时,再拿出来使用, 从而在一定情况下减少创造对象所产生的开销。但是不是任何对象都适合使用对象池,因为维护对象池也需要一定的开支。一定要“维护对象池的开支”小于“创建对象的开支”。

线程池:基本思想任然是对象池的思想,在开辟的一片空间里,存着很多线程,线程池的调度由池管理器来处理。当需要一个线程时,从池中取一个,用完后重新归池,减少了创建线程的开支。

java提供了ExecutorService和Executors类,我们可以用它们去创建线程池。

6.优化——回收不需要的内存

回收主要是Dalvik的GC机制。下面来讲一些具体的:

线程回收:

线程中涉及的任何东西GC都不能回收,所以线程很容易造成内存泄露。

Thread t = new Thread() {

public void run() {

while (true) {

try {

Thread.sleep(1000);

System.out.println("thread is running...");

} catch (InterruptedException e) {

}

}

}

};

t.start();

t = null;

System.gc();

这个时候GC并不会回收这个线程,因为正在运行的线程属于GCRoot的一种,并不会被GC进行回收。

游标回收:

Cursor是Android查询数据后得到的一个管理数据集合的类,应该在使用完之后立即手动进行关闭。一般使用如下:

Cursor cursor = null;

try {

cursor = mContext.getContentResolver().query(uri,null, null,null,null);

if(cursor != null) {

cursor.moveToFirst();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

if (cursor != null) {

cursor.close();

}

}

注:在CursorAdapter中应用时,我们不能直接关掉Cursor,而且CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,需要在onDestroy函数中,手动关闭。

@Override

protected void onDestroy() {

if (mAdapter != null && mAdapter.getCurosr() != null) {

mAdapter.getCursor().close();

}

super.onDestroy();

}

Receiver(接收器)回收:

当在Activity进行了Receiver注册时,需要注意最后要注销。

即调用registerReceiver(),使用完毕后调用unregisterReceiver()。

一般在onDestroy()进行回收。

@Override

protected void onDestroy() {

this.unregisterReceiver(receiver);

super.onDestroy();

}

Stream/File(流/文件)回收:

各种流/文件如:

InputStream/OutputStream,SQListeOpenHelper,SQLiteDatabase,Cursor,File,I/O,Bitmap都需要关闭。

7.优化——视图布局优化

使用HierarchyViewer查看并减少OverDraw。

ViewStub标签:可以使布局在可见与不可见之间切换,默认不可见的情况下不占用内存。

include标签:复用UI资源。

merge标签:解决include标签的问题,减少一个层级,并且方便使用。

重用系统资源:使用系统自带的资源(sdk\platforms\android-x\data\res),例如:

id

android:id="@android:id/list"

字符串

@android:string/yes

Style

android:textAppearance="?android:attr/textAppearanceMedium"

颜色

android:background ="@android:color/transparent"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值