第一:不要为Context长期保存引用(要引用Context就要使得引用对象和它本身的生命周期保持一致)。
第二:如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题
第三:在你不控制对象的生命周期的情况下避免在你的Activity中使用static变量。尽量使用WeakReference去代替一个static。
第四:垃圾回收器并不保证能准确回收内存,这样在使用自己需要的内容时,主要生命周期和及时释放掉不需要的对象。尽量在Activity的生命周期结束时,在onDestroy中把我们做引用的其他对象做释放,比如:cursor.close()。
转自:http://www.cnblogs.com/wanqieddy/archive/2011/11/25/2263381.html 尽量不要使用setImageBitmap或setImageResource或BitmapFactory.decodeResource来设置一张大图,因为这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常另外,decodeStream直接拿的图片来读取字节码了, 不会根据机器的各种分辨率来自动适应, 使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源, 否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
另外,以下方式也大有帮助:
1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
BitmapFactory.Options options=new BitmapFactory.Options();
options.inJustDecodeBounds = false;
options.inSampleSize = 10; //width,hight设为原来的十分一
Bitmap btp =BitmapFactory.decodeStream(is,null,options);
2. if(!bmp.isRecycle() ){
bmp.recycle() //回收图片所占的内存
system.gc() //提醒系统及时回收
}
以下奉上一个方法:
Java代码
1. /**
2. * 以最省内存的方式读取本地资源的图片
3. * @param context
4. * @param resId
5. * @return
6. */
7. public static Bitmap readBitMap(Context context, int resId){
8. BitmapFactory.Options opt = new BitmapFactory.Options();
9. opt.inPreferredConfig = Bitmap.Config.RGB_565;
10. opt.inPurgeable = true;
11. opt.inInputShareable = true;
12. //获取资源图片
13. InputStream is = context.getResources().openRawResource(resId);
14. return BitmapFactory.decodeStream(is,null,opt);
15. }
================================================================================
Android内存溢出的解决办法
转自:http://www.cppblog.com/iuranus/archive/2010/11/15/124394.html?opt=admin
昨天在模拟器上给gallery放入图片的时候,出现java.lang.OutOfMemoryError: bitmap size exceeds VM budget 异常,图像大小超过了RAM内存。
模拟器RAM比较小,只有8M内存,当我放入的大量的图片(每个100多K左右),就出现上面的原因。
由于每张图片先前是压缩的情况,放入到Bitmap的时候,大小会变大,导致超出RAM内存,具体解决办法如下:
//解决加载图片 内存溢出的问题
//Options 只保存图片尺寸大小,不保存图片到内存
BitmapFactory.Options opts = new BitmapFactory.Options();
//缩放的比例,缩放是很难按准备的比例进行缩放的,其值表明缩放的倍数,SDK中建议其值是2的指数值,值越大会导致图片不清晰
opts.inSampleSize = 4;
Bitmap bmp = null;
bmp = BitmapFactory.decodeResource(getResources(), mImageIds[position],opts);
...
//回收
bmp.recycle();
通过上面的方式解决了,但是这并不是最完美的解决方式。
通过一些了解,得知如下:
优化Dalvik虚拟机的堆内存分配
对 于Android平台来说,其托管层使用的Dalvik Java VM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体 原理我们可以参考开源工程,这里我们仅说下使用方法: private final static float TARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate时就可以调用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
Android堆内存也可自己定义大小
对于一些Android项目,影响性能瓶颈的主要是Android自己内存管理机制问题,目前手机厂商对RAM都比较吝啬,对于软件的流畅性来说RAM对 性能的影响十分敏感,除了 优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理
bitmap 设置图片尺寸,避免 内存溢出 OutOfMemoryError的优化方法
★android 中用bitmap 时很容易内存溢出,报如下错误:Java.lang.OutOfMemoryError : bitmap size exceeds VM budget
● 主要是加上这段:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
● eg1:(通过Uri取图片)
private ImageView preview;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一
Bitmap bitmap = BitmapFactory.decodeStream(cr
.openInputStream(uri), null, options);
preview.setImageBitmap(bitmap);
以上代码可以优化内存溢出,但它只是改变图片大小,并不能彻底解决内存溢出。
● eg2:(通过路径去图片)
private ImageView preview;
private String fileName= "/sdcard/DCIM/Camera/2010-05-14 16.01.44.jpg";
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一
Bitmap b = BitmapFactory.decodeFile(fileName, options);
preview.setImageBitmap(b);
filePath.setText(fileName);
★Android 还有一些性能优化的方法:
● 首先内存方面,可以参考 Android堆内存也可自己定义大小 和 优化Dalvik虚拟机的堆内存分配
● 基础类型上,因为Java没有实际的指针,在敏感运算方面还是要借助NDK来完成。Android123提示游戏开发者,这点比较有意思的是Google 推出NDK可能是帮助游戏开发人员,比如OpenGL ES的支持有明显的改观,本地代码操作图形界面是很必要的。
● 图形对象优化,这里要说的是Android上的Bitmap对象销毁,可以借助recycle()方法显示让GC回收一个Bitmap对象,通常对一个不用的Bitmap可以使用下面的方式,如
if(bitmapObject.isRecycled()==false) //如果没有回收
bitmapObject.recycle();
● 目前系统对动画支持比较弱智对于常规应用的补间过渡效果可以,但是对于游戏而言一般的美工可能习惯了GIF方式的统一处理,目前Android系统仅能预览GIF的第一帧,可以借助J2ME中通过线程和自己写解析器的方式来读取GIF89格式的资源。
● 对于大多数Android手机没有过多的物理按键可能我们需要想象下了做好手势识别 GestureDetector 和重力感应来实现操控。通常我们还要考虑误操作问题的降噪处理。
Android堆内存也可自己定义大小
对于一些大型Android项目或游戏来说在算法处理上没有问题外,影响性能瓶颈的主要是Android自己内存管理机制问题,目前手机厂商对RAM都比 较吝啬,对于软件的流畅性来说RAM对性能的影响十分敏感,除了上次Android开发网提到的 优化Dalvik虚拟机的堆内存分配外,我们还可以强制定义自己软件的对内存大小,我们使用Dalvik提供的 dalvik.system.VMRuntime类来设置最小堆内存为例:
private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE); //设置最小heap内存为6MB大小。当然对于内存吃紧来说还可以通过手动干涉GC去处理,我们将在下次提到具体应用。
优化Dalvik虚拟机的堆内存分配
对 于Android平台来说,其托管层使用的Dalvik JavaVM从目前的表现来看还有很多地方可以优化处理,比如我们在开发一些大型游戏或耗资源的应用中可能考虑手动干涉GC处理,使用 dalvik.system.VMRuntime类提供的setTargetHeapUtilization方法可以增强程序堆内存的处理效率。当然具体 原理我们可以参考开源工程,这里我们仅说下使用方法: private final static floatTARGET_HEAP_UTILIZATION = 0.75f; 在程序onCreate时就可以调用 VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION); 即可。
介绍一下图片占用进程的内存算法吧。
android中处理图片的基础类是Bitmap,顾名思义,就是位图。占用内存的算法如下:
图片的width*height*Config。
如果Config设置为ARGB_8888,那么上面的Config就是4。一张480*320的图片占用的内存就是480*320*4 byte。
前面有人说了一下8M的概念,其实是在默认情况下android进程的内存占用量为16M,因为Bitmap他除了java中持有数据外,底层C++的 skia图形库还会持有一个SKBitmap对象,因此一般图片占用内存推荐大小应该不超过8M。这个可以调整,编译源代码时可以设置参数。
转自:http://mzh3344258.blog.51cto.com/1823534/804237
- Object o=new Object();
- Object o1=o;
- o=null;
- o1=null
- String abc=new String("abc"); //1
- SoftReference<String> abcSoftRef=new SoftReference<String>(abc); //2
- WeakReference<String> abcWeakRef = new WeakReference<String>(abc); //3
- abc=null; //4
- abcSoftRef.clear();//5
- Reference(T paramT, ReferenceQueue<? super T>paramReferenceQueue)
- A obj = new A();
- Refenrence sr = new SoftReference(obj);
- //引用时
- if(sr!=null){
- obj = sr.get();
- }else{
- obj = new A();
- sr = new SoftReference(obj);
- }
- String abc=new String("abc");
- WeakReference<String> abcWeakRef = new WeakReference<String>(abc);
- abc=null;
- System.out.println("before gc: "+abcWeakRef.get());
- System.gc();
- System.out.println("after gc: "+abcWeakRef.get());
- A obj = new A();
- WeakReference wr = new WeakReference(obj);
- obj = null;
- //等待一段时间,obj对象就会被垃圾回收
- ...
- if (wr.get()==null) {
- System.out.println("obj 已经被清除了 ");
- } else {
- System.out.println("obj 尚未被清除,其信息是 "+obj.toString());
- }
- ...
- }
- import java.lang.ref.PhantomReference;
- import java.lang.ref.Reference;
- import java.lang.ref.ReferenceQueue;
- import java.lang.reflect.Field;
- public class Test {
- public static boolean isRun = true;
- public static void main(String[] args) throws Exception {
- String abc = new String("abc");
- System.out.println(abc.getClass() + "@" + abc.hashCode());
- final ReferenceQueue referenceQueue = new ReferenceQueue<String>();
- new Thread() {
- public void run() {
- while (isRun) {
- Object o = referenceQueue.poll();
- if (o != null) {
- try {
- Field rereferent = Reference.class
- .getDeclaredField("referent");
- rereferent.setAccessible(true);
- Object result = rereferent.get(o);
- System.out.println("gc will collect:"
- + result.getClass() + "@"
- + result.hashCode());
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- }.start();
- PhantomReference<String> abcWeakRef = new PhantomReference<String>(abc,
- referenceQueue);
- abc = null;
- Thread.currentThread().sleep(3000);
- System.gc();
- Thread.currentThread().sleep(3000);
- isRun = false;
- }
- }
- @SuppressWarnings("unused")
- private Bitmap copressImage(String imgPath){
- File picture = new File(imgPath);
- Options bitmapFactoryOptions = new BitmapFactory.Options();
- //下面这个设置是将图片边界不可调节变为可调节
- bitmapFactoryOptions.inJustDecodeBounds = true;
- bitmapFactoryOptions.inSampleSize = 2;
- int outWidth = bitmapFactoryOptions.outWidth;
- int outHeight = bitmapFactoryOptions.outHeight;
- bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
- bitmapFactoryOptions);
- float imagew = 150;
- float imageh = 150;
- int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
- / imageh);
- int xRatio = (int) Math
- .ceil(bitmapFactoryOptions.outWidth / imagew);
- if (yRatio > 1 || xRatio > 1) {
- if (yRatio > xRatio) {
- bitmapFactoryOptions.inSampleSize = yRatio;
- } else {
- bitmapFactoryOptions.inSampleSize = xRatio;
- }
- }
- bitmapFactoryOptions.inJustDecodeBounds = false;
- bmap = BitmapFactory.decodeFile(picture.getAbsolutePath(),
- bitmapFactoryOptions);
- if(bmap != null){
- //ivwCouponImage.setImageBitmap(bmap);
- return bmap;
- }
- return null;
- }
- package com.lvguo.scanstreet.activity;
- import java.io.File;
- import java.lang.ref.SoftReference;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import android.app.Activity;
- import android.app.AlertDialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.content.Intent;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.BitmapFactory;
- import android.graphics.BitmapFactory.Options;
- import android.os.Bundle;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.WindowManager;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemLongClickListener;
- import android.widget.BaseAdapter;
- import android.widget.Gallery;
- import android.widget.ImageView;
- import android.widget.Toast;
- import com.lvguo.scanstreet.R;
- import com.lvguo.scanstreet.data.ApplicationData;
- /**
- * @Title: PhotoScanActivity.java
- * @Description: 照片预览控制类
- * @author XiaoMa
- */
- public class PhotoScanActivity extends Activity {
- private Gallery gallery ;
- private List<String> ImageList;
- private List<String> it ;
- private ImageAdapter adapter ;
- private String path ;
- private String shopType;
- private HashMap<String, SoftReference<Bitmap>> imageCache = null;
- private Bitmap bitmap = null;
- private SoftReference<Bitmap> srf = null;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
- setContentView(R.layout.photoscan);
- Intent intent = this.getIntent();
- if(intent != null){
- if(intent.getBundleExtra("bundle") != null){
- Bundle bundle = intent.getBundleExtra("bundle");
- path = bundle.getString("path");
- shopType = bundle.getString("shopType");
- }
- }
- init();
- }
- private void init(){
- imageCache = new HashMap<String, SoftReference<Bitmap>>();
- gallery = (Gallery)findViewById(R.id.gallery);
- ImageList = getSD();
- if(ImageList.size() == 0){
- Toast.makeText(getApplicationContext(), "无照片,请返回拍照后再使用预览", Toast.LENGTH_SHORT).show();
- return ;
- }
- adapter = new ImageAdapter(this, ImageList);
- gallery.setAdapter(adapter);
- gallery.setOnItemLongClickListener(longlistener);
- }
- /**
- * Gallery长按事件操作实现
- */
- private OnItemLongClickListener longlistener = new OnItemLongClickListener() {
- @Override
- public boolean onItemLongClick(AdapterView<?> parent, View view,
- final int position, long id) {
- //此处添加长按事件删除照片实现
- AlertDialog.Builder dialog = new AlertDialog.Builder(PhotoScanActivity.this);
- dialog.setIcon(R.drawable.warn);
- dialog.setTitle("删除提示");
- dialog.setMessage("你确定要删除这张照片吗?");
- dialog.setPositiveButton("确定", new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- File file = new File(it.get(position));
- boolean isSuccess;
- if(file.exists()){
- isSuccess = file.delete();
- if(isSuccess){
- ImageList.remove(position);
- adapter.notifyDataSetChanged();
- //gallery.setAdapter(adapter);
- if(ImageList.size() == 0){
- Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoSizeZero), Toast.LENGTH_SHORT).show();
- }
- Toast.makeText(getApplicationContext(), getResources().getString(R.string.phoDelSuccess), Toast.LENGTH_SHORT).show();
- }
- }
- }
- });
- dialog.setNegativeButton("取消",new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- }
- });
- dialog.create().show();
- return false;
- }
- };
- /**
- * 获取SD卡上的所有图片文件
- * @return
- */
- private List<String> getSD() {
- /* 设定目前所在路径 */
- File fileK ;
- it = new ArrayList<String>();
- if("newadd".equals(shopType)){
- //如果是从查看本人新增列表项或商户列表项进来时
- fileK = new File(ApplicationData.TEMP);
- }else{
- //此时为纯粹新增
- fileK = new File(path);
- }
- File[] files = fileK.listFiles();
- if(files != null && files.length>0){
- for(File f : files ){
- if(getImageFile(f.getName())){
- it.add(f.getPath());
- Options bitmapFactoryOptions = new BitmapFactory.Options();
- //下面这个设置是将图片边界不可调节变为可调节
- bitmapFactoryOptions.inJustDecodeBounds = true;
- bitmapFactoryOptions.inSampleSize = 5;
- int outWidth = bitmapFactoryOptions.outWidth;
- int outHeight = bitmapFactoryOptions.outHeight;
- float imagew = 150;
- float imageh = 150;
- int yRatio = (int) Math.ceil(bitmapFactoryOptions.outHeight
- / imageh);
- int xRatio = (int) Math
- .ceil(bitmapFactoryOptions.outWidth / imagew);
- if (yRatio > 1 || xRatio > 1) {
- if (yRatio > xRatio) {
- bitmapFactoryOptions.inSampleSize = yRatio;
- } else {
- bitmapFactoryOptions.inSampleSize = xRatio;
- }
- }
- bitmapFactoryOptions.inJustDecodeBounds = false;
- bitmap = BitmapFactory.decodeFile(f.getPath(),
- bitmapFactoryOptions);
- //bitmap = BitmapFactory.decodeFile(f.getPath());
- srf = new SoftReference<Bitmap>(bitmap);
- imageCache.put(f.getName(), srf);
- }
- }
- }
- return it;
- }
- /**
- * 获取图片文件方法的具体实现
- * @param fName
- * @return
- */
- private boolean getImageFile(String fName) {
- boolean re;
- /* 取得扩展名 */
- String end = fName
- .substring(fName.lastIndexOf(".") + 1, fName.length())
- .toLowerCase();
- /* 按扩展名的类型决定MimeType */
- if (end.equals("jpg") || end.equals("gif") || end.equals("png")
- || end.equals("jpeg") || end.equals("bmp")) {
- re = true;
- } else {
- re = false;
- }
- return re;
- }
- public class ImageAdapter extends BaseAdapter{
- /* 声明变量 */
- int mGalleryItemBackground;
- private Context mContext;
- private List<String> lis;
- /* ImageAdapter的构造符 */
- public ImageAdapter(Context c, List<String> li) {
- mContext = c;
- lis = li;
- TypedArray a = obtainStyledAttributes(R.styleable.Gallery);
- mGalleryItemBackground = a.getResourceId(R.styleable.Gallery_android_galleryItemBackground, 0);
- a.recycle();
- }
- /* 几定要重写的方法getCount,传回图片数目 */
- public int getCount() {
- return lis.size();
- }
- /* 一定要重写的方法getItem,传回position */
- public Object getItem(int position) {
- return lis.get(position);
- }
- /* 一定要重写的方法getItemId,传并position */
- public long getItemId(int position) {
- return position;
- }
- /* 几定要重写的方法getView,传并几View对象 */
- public View getView(int position, View convertView, ViewGroup parent) {
- System.out.println("lis:"+lis);
- File file = new File(it.get(position));
- SoftReference<Bitmap> srf = imageCache.get(file.getName());
- Bitmap bit = srf.get();
- ImageView i = new ImageView(mContext);
- i.setImageBitmap(bit);
- i.setScaleType(ImageView.ScaleType.FIT_XY);
- i.setLayoutParams( new Gallery.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT));
- return i;
- }
- }
- }
- 1. InputStream is = this.getResources().openRawResource(R.drawable.pic1);
- BitmapFactory.Options options=new BitmapFactory.Options();
- options.inJustDecodeBounds = false;
- options.inSampleSize = 10; //width,hight设为原来的十分一
- Bitmap btp =BitmapFactory.decodeStream(is,null,options);
- 2. if(!bmp.isRecycle() ){
- bmp.recycle() //回收图片所占的内存
- system.gc() //提醒系统及时回收
- }
- /** 这个地方大家别搞混了,为了方便小马把两个贴一起了,使用的时候记得分开使用
- * 以最省内存的方式读取本地资源的图片
- */
- public static Bitmap readBitMap(Context context, int resId){
- BitmapFactory.Options opt = new BitmapFactory.Options();
- opt.inPreferredConfig = Bitmap.Config.RGB_565;
- opt.inPurgeable = true;
- opt.inInputShareable = true;
- //获取资源图片
- InputStream is = context.getResources().openRawResource(resId);
- return BitmapFactory.decodeStream(is,null,opt);
- }
- if(bitmapObject.isRecycled()==false) //如果没有回收
- bitmapObject.recycle();
- private final static floatTARGET_HEAP_UTILIZATION = 0.75f;
- 在程序onCreate时就可以调用
- VMRuntime.getRuntime().setTargetHeapUtilization(TARGET_HEAP_UTILIZATION);
- 即可
- private final static int CWJ_HEAP_SIZE = 6* 1024* 1024 ;
- //设置最小heap内存为6MB大小
- VMRuntime.getRuntime().setMinimumHeapSize(CWJ_HEAP_SIZE);