Android编程内存溢出与防范方法浅析

本文实例讲述了Android编程内存溢出与防范方法。分享给大家供大家参考,具体如下:

Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M。但是Android采用的是Java语言编写,所以在很大程度上,Android的内存机制等同于Java的内存机制,在刚开始开发的时候,内存的限制问题会给我们带来内存溢出等严重问题。在我们不使用一些内存的时候,我们要尽量在Android或者其他平台上避免在运行其他程序时,保存必要的状态,使得一些死进程所带来的内存问题,应该尽量在关闭程序或者保存状态的时候释放掉,这样能提高系统在运行方面的流畅性。

Android的内存主要表现在:

1. 在Android平台上,长期保持一些资源的引用,造成一些内存不能释放,带来的内存泄露问题很多。比如:Context(下文中提到的Activity都是Context),在一些你需要保持你的首个类对象状态,并且把状态传入其他类对象中时,这样消除掉首个类对象之前,你必须先把接收类对象释放掉。需要注意一点的是:因为在Java或者Android内存机制中,顶点的结点释放前必须保证其他对象没有调用才能被系统GC回收释放。我们来看一段代码:

@Override protected void onCreate(Bundle state) { super.onCreate(state); TextViewlabel = new TextView(this); label.setText("Leaksare bad"); setContentView(label); }

这个代码的意思就是我们把一个TextView的实例加载到了我们正在运行的Activity(Context)当中,因此,通过GC回收机制,我们知道,要释放Context,就必须先释放掉引用他的一些对象。如果没有,那在要释放Context的时候,你会发现会有大量的内存溢出。所以在你不小心的情况下内存溢出是一件非常容易的事情。 保存一些对象时,同时也会造成内存泄露。最简单的比如说位图(Bitmap),比如说:在屏幕旋转时,会破坏当前保持的一个Activity状态,并且重新申请生成新的Activity,直到新的Activity状态被保存。我们再看一段代码:

privatestatic Drawable sBackground; @Override protected void onCreate(Bundle state) { super.onCreate(state); TextView label = new TextView(this); label.setText("Leaks are bad"); if (sBackground == null) { sBackground =getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground); setContentView(label); }

这个代码是非常快的同时也是错误的。它的内存泄露很容易出在屏幕转移的方向上。虽然我们会发现没有显示的保存Context这个实例,但是当我们把绘制的图连接到一个视图的时候,Drawable就会将被View设置为回调,这就说明,在上述的代码中,其实在绘制TextView到活动中的时候,我们已经引用到了这个Activity。链接情况可以表现为:Drawable->TextView->Context。

所以在想要释放Context的时候,其实还是保存在内存中,并没有得到释放。

如何避免这种情况:主要在于。线程最容易出错。大家不要小看线程,在Android里面线程最容易造成内存泄露。线程产生内存泄露的主要原因在于线程生命周期的不可控。下面有一段代码:

publicclass MyTest extends Activity { @Override publicvoid onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); new MyThread().start(); } privateclass 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。

2. 万恶的bitmap。。。

Bitmap是一个很万恶的对象,对于一个内存对象,如果该对象所占内存过大,在超出了系统的内存限制时候,内存泄露问题就很明显了。。
解决bitmap主要是要解决在内存尽量不保存它或者使得采样率变小。在很多场合下,因为我们的图片像素很高,而对于手机屏幕尺寸来说我们并不用那么高像素比例的图片来加载时,我们就可以先把图片的采样率降低在做原来的UI操作。

如果在我们不需要保存bitmap对象的引用时候,我们还可以用软引用来做替换。具体的实例代码google上面也有很多。

综上所述,要避免内存泄露,主要要遵循以下几点:

第一:不要为Context长期保存引用(要引用Context就要使得引用对象和它本身的生命周期保持一致)。

第二:如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题

第三:在你不控制对象的生命周期的情况下避免在你的Activity中使用static变量。尽量使用WeakReference去代替一个static。

第四:垃圾回收器并不保证能准确回收内存,这样在使用自己需要的内容时,主要生命周期和及时释放掉不需要的对象。尽量在Activity的生命周期结束时,在onDestroy中把我们做引用的其他对象做释放,比如:cursor.close()。

其实我们可以在很多方面使用更少的代码去完成程序。比如:我们可以多的使用9patch图片等。有很多细节地方都可以值得我们去发现、挖掘更多的内存问题。我们要是能做到C/C++对于程序的“谁创建,谁释放”原则,那我们对于内存的把握,并不比Java或Android本身的GC机制差,而且更好的控制内存,能使我们的手机运行得更流畅。

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android开发之内存与缓存技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android多媒体操作技巧汇总(音频,视频,录音等)》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

时间: 2024-07-31 15:56:48

Android编程内存溢出与防范方法浅析的相关文章

Android编程内存溢出与防范方法浅析_Android

本文实例讲述了Android编程内存溢出与防范方法.分享给大家供大家参考,具体如下:  Android的虚拟机是基于寄存器的Dalvik,它的最大堆大小一般是16M.但是Android采用的是Java语言编写,所以在很大程度上,Android的内存机制等同于Java的内存机制,在刚开始开发的时候,内存的限制问题会给我们带来内存溢出等严重问题.在我们不使用一些内存的时候,我们要尽量在Android或者其他平台上避免在运行其他程序时,保存必要的状态,使得一些死进程所带来的内存问题,应该尽量在关闭程序

Android编程实现状态保存的方法分析

本文实例讲述了Android编程实现状态保存的方法.分享给大家供大家参考,具体如下: 1.当我们正在发短信的时候,已经写了几百字了,这时突然来了一个电话,我们接完电话之后,如果发现辛辛苦苦的几百字不见了,那可就火大了,而实际上这些内容都是保存了的.在我们接电话的过程中,我们发信息的那个Activity是可能会被系统回收的,这时会调用Activity的onSaveInstanceState回调方法,而我们就可以在这个方法中保存状态数据,在onCreate方法或者在2.0之后提供的回调方法onRes

Android编程获取图片数据的方法详解

本文实例讲述了Android编程获取图片数据的方法.分享给大家供大家参考,具体如下: 网络的访问在我们日常生活中太重要了,如果没有网络我们的生活将会是什么样子呢?Android手机和浏览器也是一样的,也可以通过网络通讯获取数据,如调用webservice,EJB等.下面就通过一个小例子从网络获取一幅图片并显示在手机上,开发中将会使用到一个新的组件ImageView. 1. 写一个用来处理字节流的工具类 package org.lxh.util; import java.io.ByteArrayO

Android编程设置全屏的方法实例

  Android编程设置全屏的方法实例          本文实例讲述了Android编程设置全屏的方法.分享给大家供大家参考,具体如下: 在实际的应用程序开发中,我们有时需要把 Activity 设置成全屏显示,一般情况下,可以通过两种方式来设置全屏显示效果.其一,通过在代码中可以设置,其二,通过manifest配置文件来设置全屏. 其一:在代码中设置(如下) package xiaohang.zhimeng; import android.app.Activity; import andr

Android编程Widget创建与使用方法简明教程_Android

本文实例讲述了Android编程Widget创建与使用方法.分享给大家供大家参考,具体如下: Android reference中有关于如何建立一个Widget的详细方法,这里简要说明一下,详情可以查看Android SDK中自带的reference. 要建立一个Widget,分为如下几个步骤: (1) 创建一个类,让其继承类AppWidgetProvider,在AppWidgetProvider中有许多方法,例如onDelete(Context,int[]),onEnable(Context)

Android编程之阴影(Shadow)制作方法_Android

本文实例讲述了Android编程之阴影(Shadow)制作方法.分享给大家供大家参考,具体如下: 先看运行效果图如下: 阴影制作:包括各种形状(矩形,圆形等等),以及文字等等都能设置阴影. 阴影制作是什么原理呢? 其实很简单,你需要设置阴影的东西被看作一个主层.然后在主层下面画一个阴影层. 阴影制作涉及到一个重要函数: public void setShadowLayer (float radius, float dx, float dy, int color) 参数: radius:阴影半径

Android编程实现自定义手势的方法详解_Android

本文实例讲述了Android编程实现自定义手势的方法.分享给大家供大家参考,具体如下: 之前介绍过如何在Android程序中使用手势,主要是系统默认提供的几个手势,这次介绍一下如何自定义手势,以及如何对其进行管理. 先介绍一下Android系统对手势的管理,Android系统允许应用程序把用户的手势以文件的形式保存以前,以后要使用这些手势只需要加载这个手势库文件即可,同时Android系统还提供了诸如手势识别.查找及删除等的函数接口,具体如下: 一.加载手势库文件: staticGestureL

Android编程获取GPS数据的方法详解_Android

本文实例讲述了Android编程获取GPS数据的方法.分享给大家供大家参考,具体如下: GPS是Android系统中重要的组成部分,通过它可以衍生出众多的与位置相关的应用. Android的GPS有一个专门的管理类,称为LocationManager,所有的GPS定位服务都由其对象产生并进行控制. 首先需要明确的是,LocationManager类的对象获取并不是直接创建的,而是由系统提供的,具体来说,通过如下方法,为一个LocationManager对象建立一个对象引用: 复制代码 代码如下:

Android编程绘制圆形图片的方法_Android

本文实例讲述了Android编程绘制圆形图片的方法.分享给大家供大家参考,具体如下: 效果图如下: 第一步:新建RoundView自定义控件继承View package com.rong.activity; import com.rong.test.R; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.grap