Android 内存浅析【泄漏、溢出】【二】
2012-10-01 23:08
274 查看
内存溢出之Bitmap
可以说出现OutOfMemory问题的绝大多数人,都是因为Bitmap的问题。因为Bitmap占用的内存实在是太多了,它是一个“超级大胖子”,特别是分辨率大的图片,如果要显示多张那问题就更显著了。
如何解决Bitmap带给我们的内存问题?
第一、及时销毁。
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。所以Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null. 虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。
第二、设置一定的采样率。
手机就那么屁大的屏幕,所以有时候我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。如下面的代码:
第三、巧妙的运用软引用(SoftRefrence)
有些时候,我们使用Bitmap后没有保留对它的引用,因此就无法调用Recycle函数。这时候巧妙的运用软引用,可以使Bitmap在内存快不足时得到有效的释放。
内存溢出之Adapter
构造 Adapter时,没有使用缓存的 convertView
以构造ListView的 BaseAdapter 为例,在BaseAdapter 中提共了方public View getView(int position, View convertView, ViewGroup pare来向ListView提供每一个item所需要的view对象。初始时ListBaseAdapter 中根据当前的屏幕布局实例化一定数量的view对象,同些view对象缓存起来。当向上滚动ListView时,原先位于最上面的象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程方法完成的,getView()的第二个形参
View convertView就是被缓存起view对象(初始化时缓存中没有view对象则convertView是null)。
由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。构造 Adapter时,没有使用缓存的 convertView
以构造ListView的 BaseAdapter 为例,在BaseAdapter 中提共了方法:
public View getView(int position, View convertView, ViewGroup parent) 来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter 中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参
View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。
所以综合以上的理论,写了一个小例子,表达一下:
内存溢出之Cursor
Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,操作小数据查询时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。 然而如果Cursor的数据量特别大,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android 文档中提倡开发者手动的关闭Cursor。
所以我们最好这样使用Cursor:
但在CursorAdapter中应用的情况下,必须注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭:
可以说出现OutOfMemory问题的绝大多数人,都是因为Bitmap的问题。因为Bitmap占用的内存实在是太多了,它是一个“超级大胖子”,特别是分辨率大的图片,如果要显示多张那问题就更显著了。
如何解决Bitmap带给我们的内存问题?
第一、及时销毁。
虽然,系统能够确认Bitmap分配的内存最终会被销毁,但是由于它占用的内存过多,所以很可能会超过java堆的限制。因此,在用完Bitmap时,要及时的recycle掉。recycle并不能确定立即就会将Bitmap释放掉,但是会给虚拟机一个暗示:“该图片可以释放了”。所以Bitmap对象在不使用时,我们应该先调用recycle()释放内存,然后才它设置为null. 虽然recycle()从源码上看,调用它应该能立即释放Bitmap的主要内存,但是测试结果显示它并没能立即释放内存。
if(!bitmap.isRecycled()){ bitmap.recycle(); bitmap = null; }
第二、设置一定的采样率。
手机就那么屁大的屏幕,所以有时候我们要显示的区域很小,没有必要将整个图片都加载出来,而只需要记载一个缩小过的图片,这时候可以设置一定的采样率,那么就可以大大减小占用的内存。如下面的代码:
public ImageView iv ; public void example() { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;// 图片宽高都为原来的二分之一,即图片为原来的四分之一。数值越大图片越模糊.你懂的 //Uri u = Uri.parse( "content://media/internal/audio/media/81" ); // Bitmap bitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(Uri.parse(uriString)), null, options); Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher, options); iv.setImageBitmap(bitmap); }
第三、巧妙的运用软引用(SoftRefrence)
有些时候,我们使用Bitmap后没有保留对它的引用,因此就无法调用Recycle函数。这时候巧妙的运用软引用,可以使Bitmap在内存快不足时得到有效的释放。
内存溢出之Adapter
构造 Adapter时,没有使用缓存的 convertView
以构造ListView的 BaseAdapter 为例,在BaseAdapter 中提共了方public View getView(int position, View convertView, ViewGroup pare来向ListView提供每一个item所需要的view对象。初始时ListBaseAdapter 中根据当前的屏幕布局实例化一定数量的view对象,同些view对象缓存起来。当向上滚动ListView时,原先位于最上面的象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程方法完成的,getView()的第二个形参
View convertView就是被缓存起view对象(初始化时缓存中没有view对象则convertView是null)。
由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费时间,也造成内存垃圾,给垃圾回收增加压力,如果垃圾回收来不及的话,虚拟机将不得不给该应用进程分配更多的内存,造成不必要的内存开支。构造 Adapter时,没有使用缓存的 convertView
以构造ListView的 BaseAdapter 为例,在BaseAdapter 中提共了方法:
public View getView(int position, View convertView, ViewGroup parent) 来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter 中根据当前的屏幕布局实例化一定数量的view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参
View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。
所以综合以上的理论,写了一个小例子,表达一下:
/** * ****************************************** * @author 老牛比 * 文件名称 : ExampleAdapter.java * 创建时间 : 2012-10-1 下午11:11:28 * 文件描述 : 优化小例子 ****************************************** */ public class ExampleAdapter extends BaseAdapter { private ArrayList<SoftReference<Bitmap>> mBitmaps = new ArrayList<SoftReference<Bitmap>>(); private ArrayList<Object> mValues; private LayoutInflater mInflater; public ExampleAdapter(ArrayList<SoftReference<Bitmap>> mBitmaps, ArrayList<Object> mValues, Context mContext, LayoutInflater mInflater) { super(); this.mValues = mValues; this.mInflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public int getCount() { return mValues.size(); } public Object getItem(int position) { return mValues.get(position); } public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; Bitmap bitmap = BitmapFactory.decodeFile(mValues.get(position).XXX); mBitmaps.add(new SoftReference<Bitmap>(bitmap)); // 此处加入ArrayList if (convertView == null) { convertView = mInflater.inflate(R.layout.example, false); holder = new ViewHolder(); holder.text = (TextView) convertView.findViewById(R.id.text); holder.icon = (ImageView) convertView.findViewById(R.id.icon); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.text.setText("xxx"); holder.icon.setImageBitmap(bitmap); return convertView; } /** * ****************************************** * @author 老牛比 * 文件名称 : ViewHolder.java * 创建时间 : 2012-10-1 下午10:35:25 * 文件描述 : 使用 ViewHolder 模式, 效率再提高 50% ****************************************** */ class ViewHolder { TextView text; ImageView icon; } }
内存溢出之Cursor
Cursor是Android查询数据后得到的一个管理数据集合的类,正常情况下,操作小数据查询时不会有内存问题,而且虚拟机能够保证Cusor最终会被释放掉。 然而如果Cursor的数据量特别大,应该保证Cursor占用的内存被及时的释放掉,而不是等待GC来处理。并且Android 文档中提倡开发者手动的关闭Cursor。
所以我们最好这样使用Cursor:
public void example() { Cursor mCursor = null; try { mCursor = mContext.getContentResolver().query(uri, null, null, null, null); if (mCursor != null) { mCursor.moveToFirst(); // TODO:do something } } catch (Exception e) { e.printStackTrace(); } finally { if (mCursor != null) { mCursor.close(); } } }
但在CursorAdapter中应用的情况下,必须注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭:
@Override protected void onDestroy() { if (mAdapter != null && mAdapter.getCurosr() != null) { mAdapter.getCursor().close(); } super.onDestroy(); }
相关文章推荐
- Android 内存浅析【二】【泄漏、溢出】
- Android 内存浅析【泄漏、溢出】【一】
- Android防止内存溢出浅析
- Android防止内存溢出浅析
- android防止内存溢出浅析(二)
- Android防止内存溢出浅析
- Android防止内存溢出浅析
- Android之内存泄漏检测LeakCanary原理浅析
- 【android开发】Android防止内存溢出浅析
- android防止内存溢出浅析
- 【android开发】Android防止内存溢出浅析
- 浅析Android防止内存溢出问题
- android防止内存溢出浅析
- 【android开发】Android防止内存溢出浅析
- Android防止内存溢出浅析
- Android防止内存溢出浅析
- 浅析Android防止内存溢出问题
- Android防止内存溢出浅析 .
- Android防止内存溢出浅析
- Android防止内存溢出浅析