Bitmap对象回收不及时导致而内存溢出,求解??

Jing丶無雙 2015-01-09 04:02:20
简述:



(图一)


(图二)



(图三)
我的应用先是要读取300多张手机相册的图片,并依次装入Bitmap数组中,再以GridView形式显示在界面上(如图一丶二)。当摧毁这个activity时我调用了
	@Override
protected void onDestroy() {
super.onDestroy();
for (int i = 0; i < bmp.length; i++) {
if (bmp[i] != null) {
bmp[i].recycle();
bmp[i] = null;
}
}
System.gc();
}

这里回收Bitmap数组,但是当我跳往手机拍照activity时,按下快门得到数据并解析为Bitmap对象时就报了OOM的错误(如图三)


以下贴出相关代码:

1.根据手机图片的路径解析得到bitmap实例:
/**
* 判断GridView是否停止滑动
**/
private void isGridViewStop() {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;// 图片宽高都为原来的4分之一,即图片为原来的16分之一
gvSelect.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:// 滑动停止
for (; start_index < end_index; start_index++) {
try {
if (bmp[start_index] == null) {// 优化读取本地图片
bmp[start_index] = BitmapFactory.decodeFile(
imagePath[start_index], options);
// 对原位图进行缩放
bmp[start_index] = Bitmap.createScaledBitmap(
bmp[start_index], 165, 165, true);
}
} catch (Exception e) {
Log.d("空指针1", bmp[start_index] + "");

}
}
adapter.notifyDataSetChanged();
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 滚动
break;
default:
break;
}
}

@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 设置当前屏幕显示的起始index和结束index
start_index = firstVisibleItem;
end_index = firstVisibleItem + visibleItemCount;
}
});

}

2.按下快门,解析data得到bitmap实例

private final class TakePictureCallback implements PictureCallback {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
String sdStatus = Environment.getExternalStorageState();
if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) {
// 检测sd是否可用
Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用!",
Toast.LENGTH_LONG).show();
return;
} else {
Log.d("解码", "0*******");
// 解码指定字节数组中的一个不变的位图
bitmap = BitmapFactory.decodeByteArray(data, 0,
data.length);
Log.d("解码", "1*******");
Intent starEdit = new Intent(PhotographActivity.this,
ConfirmActivity.class);
startActivity(starEdit);
}
}
}



报错的Log日志:

01-09 15:48:47.564: I/Choreographer(20147): Skipped 50 frames! The application may be doing too much work on its main thread.
01-09 15:48:50.567: I/Choreographer(20147): Skipped 68 frames! The application may be doing too much work on its main thread.
01-09 15:48:50.778: D/解码(20147): 0*******
01-09 15:48:50.818: D/dalvikvm(20147): GC_FOR_ALLOC freed 257K, 74% free 16934K/64647K, paused 35ms, total 37ms
01-09 15:48:50.868: D/dalvikvm(20147): GC_CONCURRENT freed 10K, 50% free 48136K/95879K, paused 11ms+3ms, total 30ms

01-09 15:48:51.158: D/dalvikvm(20147): GC_FOR_ALLOC freed 2364K, 48% free 50168K/95879K, paused 31ms, total 31ms
01-09 15:48:51.198: D/dalvikvm(20147): GC_BEFORE_OOM freed 2K, 48% free 50165K/95879K, paused 39ms, total 39ms
01-09 15:48:51.198: E/dalvikvm-heap(20147): Out of memory on a 31961104-byte allocation.
01-09 15:48:51.198: I/dalvikvm(20147): "Thread-4040" prio=5 tid=13 RUNNABLE
01-09 15:48:51.198: I/dalvikvm(20147): | group="main" sCount=0 dsCount=0 obj=0x42130508 self=0x68515be0
01-09 15:48:51.198: I/dalvikvm(20147): | sysTid=20696 nice=0 sched=0/0 cgrp=apps handle=1751339088
01-09 15:48:51.198: I/dalvikvm(20147): | schedstat=( 0 0 0 ) utm=5 stm=0 core=1
01-09 15:48:51.198: I/dalvikvm(20147): at android.graphics.Bitmap.nativeCreate(Native Method)
01-09 15:48:51.198: I/dalvikvm(20147): at android.graphics.Bitmap.createBitmap(Bitmap.java:650)
01-09 15:48:51.198: I/dalvikvm(20147): at android.graphics.Bitmap.createBitmap(Bitmap.java:596)
01-09 15:48:51.198: I/dalvikvm(20147): at app.takephoto.ConfirmActivity.savePhoto(ConfirmActivity.java:150)
01-09 15:48:51.198: I/dalvikvm(20147): at app.takephoto.ConfirmActivity.access$7(ConfirmActivity.java:144)
01-09 15:48:51.198: I/dalvikvm(20147): at app.takephoto.ConfirmActivity$2.run(ConfirmActivity.java:91)
01-09 15:48:51.198: I/dalvikvm(20147): at java.lang.Thread.run(Thread.java:856)
01-09 15:48:51.198: E/dalvikvm(20147): threadid=13: exiting,name=Thread-4040
01-09 15:48:51.198: W/dalvikvm(20147): threadid=13: thread exiting with uncaught exception (group=0x416a2498)
01-09 15:48:51.198: E/AndroidRuntime(20147): FATAL EXCEPTION: Thread-4040
01-09 15:48:51.198: E/AndroidRuntime(20147): java.lang.OutOfMemoryError
01-09 15:48:51.198: E/AndroidRuntime(20147): at android.graphics.Bitmap.nativeCreate(Native Method)
01-09 15:48:51.198: E/AndroidRuntime(20147): at android.graphics.Bitmap.createBitmap(Bitmap.java:650)
01-09 15:48:51.198: E/AndroidRuntime(20147): at android.graphics.Bitmap.createBitmap(Bitmap.java:596)
01-09 15:48:51.198: E/AndroidRuntime(20147): at app.takephoto.ConfirmActivity.savePhoto(ConfirmActivity.java:150)
01-09 15:48:51.198: E/AndroidRuntime(20147): at app.takephoto.ConfirmActivity.access$7(ConfirmActivity.java:144)
01-09 15:48:51.198: E/AndroidRuntime(20147): at app.takephoto.ConfirmActivity$2.run(ConfirmActivity.java:91)
01-09 15:48:51.198: E/AndroidRuntime(20147): at java.lang.Thread.run(Thread.java:856)


很明显日志里进入了Log.d("解码", "0*******");,而没有进Log.d("解码", "1*******");。如果直接打开照相机拍照却又不会报OOM,所以我觉得应该是之前读取过多的图片,再去打开照相机拍照造成的OOM
,谢谢各位帮忙看看啦
...全文
823 18 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
开发者_android 2015-01-12
  • 打赏
  • 举报
回复
引用 17 楼 xj396282771 的回复:
[quote=引用 16 楼 dalor 的回复:] 那你就只有用这个了.
是的,我用这个Bitmap.Options压缩,发现清晰度变化不大,但是解决了OOM,估计是data太大了。早知道直接用就好了。
	private final class TakePictureCallback implements PictureCallback {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			String sdStatus = Environment.getExternalStorageState();
			if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) {
				// 检测sd是否可用
				Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用!",
						Toast.LENGTH_LONG).show();
				return;
			} else {
             BitmapFactory.Options options = new BitmapFactory.Options();
             options.inSampleSize = 2;// 图片宽高都为原来的2分之一,即图片为原来的4分之一
				Log.d("解码", "data.length=" + data.length);
				// 解码指定字节数组中的一个不变的位图
				ConfirmActivity.bitmap = BitmapFactory.decodeByteArray(data, 0,
						data.length, options);
				Log.d("解码", "1*******");
				Intent starEdit = new Intent(PhotographActivity.this,
						ConfirmActivity.class);
				startActivity(starEdit);
			}
		}
	}
[/quote] 现在的手机,拍的照片质量非常高,压缩一点,肉眼看上去不会出现明显的失真的.
Jing丶無雙 2015-01-12
  • 打赏
  • 举报
回复
引用 16 楼 dalor 的回复:
那你就只有用这个了.
是的,我用这个Bitmap.Options压缩,发现清晰度变化不大,但是解决了OOM,估计是data太大了。早知道直接用就好了。
	private final class TakePictureCallback implements PictureCallback {
		@Override
		public void onPictureTaken(byte[] data, Camera camera) {
			String sdStatus = Environment.getExternalStorageState();
			if (!sdStatus.equals(Environment.MEDIA_MOUNTED)) {
				// 检测sd是否可用
				Toast.makeText(PhotographActivity.this, "没有SD卡或SD卡不可用!",
						Toast.LENGTH_LONG).show();
				return;
			} else {
             BitmapFactory.Options options = new BitmapFactory.Options();
             options.inSampleSize = 2;// 图片宽高都为原来的2分之一,即图片为原来的4分之一
				Log.d("解码", "data.length=" + data.length);
				// 解码指定字节数组中的一个不变的位图
				ConfirmActivity.bitmap = BitmapFactory.decodeByteArray(data, 0,
						data.length, options);
				Log.d("解码", "1*******");
				Intent starEdit = new Intent(PhotographActivity.this,
						ConfirmActivity.class);
				startActivity(starEdit);
			}
		}
	}
开发者_android 2015-01-12
  • 打赏
  • 举报
回复
引用 15 楼 xj396282771 的回复:
[quote=引用 13 楼 dalor 的回复:] 额,朋友,我的意思是设置内存大小,方法,不记得,你百一下,因为我正在写代码用到imageloader,所以,就写了这几个词. 不过,如果你有大量图片下载或从本地读取,都可以用imageloader,它可以设置memoryCacheSize.
很遗憾经过上午的调试ImageLoader运用后,先成功的展示了手机相册里的图片,但跳往拍照界面后按下快门的瞬间 仍旧抛出了OOM。目前就只有用Bitmap.Options压缩下是试试了 [/quote] 那你就只有用这个了.
Jing丶無雙 2015-01-10
  • 打赏
  • 举报
回复
引用 13 楼 dalor 的回复:
额,朋友,我的意思是设置内存大小,方法,不记得,你百一下,因为我正在写代码用到imageloader,所以,就写了这几个词. 不过,如果你有大量图片下载或从本地读取,都可以用imageloader,它可以设置memoryCacheSize.
好的谢了,我再看看。实在不行的话,就只有用Bitmap.Options压缩下了
Jing丶無雙 2015-01-10
  • 打赏
  • 举报
回复
引用 13 楼 dalor 的回复:
额,朋友,我的意思是设置内存大小,方法,不记得,你百一下,因为我正在写代码用到imageloader,所以,就写了这几个词. 不过,如果你有大量图片下载或从本地读取,都可以用imageloader,它可以设置memoryCacheSize.
很遗憾经过上午的调试ImageLoader运用后,先成功的展示了手机相册里的图片,但跳往拍照界面后按下快门的瞬间 仍旧抛出了OOM。目前就只有用Bitmap.Options压缩下是试试了
开发者_android 2015-01-09
  • 打赏
  • 举报
回复
引用 5 楼 xj396282771 的回复:
[quote=引用 1 楼 u014448521 的回复:] onPictureTaken()函数里面 bitmap = BitmapFactory.decodeByteArray(data, 0,data.length); 这里试试用Bitmap.Options压缩下
引用 3 楼 dalor 的回复:
之前打开的图片没有释放也是可能的. 不过,还得觉得,应该是相机拍照的图片太大直接导致. 在得到数据时,就先对图片进行压缩处理,再使用处理后的bitmap.
我之所以没有先用Bitmap.Options压缩,是因为我们老板要求拍出来得照片清晰度要高。请问还有别的解决方案么[/quote] 清晰高是追求的目标罢了,android不像ios,有很大的内在可控. 现在的android手机,高清的照相机,拍出来的照片都几M一张,android的内存,开发人员也不能随便控制.本身这是android的短板. 你再试试设置memoryCacheSize,把它设置大一些,但我觉得,不对图片进行压缩处理,这个问题还是不能解决,更何况,应用中图片显示和操作多的话,就更容易OOM了.
引用 12 楼 xj396282771 的回复:
[quote=引用 6 楼 dalor 的回复:] 清晰高是追求的目标罢了,android不像ios,有很大的内在可控. 现在的android手机,高清的照相机,拍出来的照片都几M一张,android的内存,开发人员也不能随便控制.本身这是android的短板. 你再试试设置memoryCacheSize,把它设置大一些,但我觉得,不对图片进行压缩处理,这个问题还是不能解决,更何况,应用中图片显示和操作多的话,就更容易OOM了.
朋友问下这个memoryCacheSize的设置是哪个类里面的方法啊,弄了半天没弄出来[/quote] 额,朋友,我的意思是设置内存大小,方法,不记得,你百一下,因为我正在写代码用到imageloader,所以,就写了这几个词. 不过,如果你有大量图片下载或从本地读取,都可以用imageloader,它可以设置memoryCacheSize.
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 6 楼 dalor 的回复:
清晰高是追求的目标罢了,android不像ios,有很大的内在可控. 现在的android手机,高清的照相机,拍出来的照片都几M一张,android的内存,开发人员也不能随便控制.本身这是android的短板. 你再试试设置memoryCacheSize,把它设置大一些,但我觉得,不对图片进行压缩处理,这个问题还是不能解决,更何况,应用中图片显示和操作多的话,就更容易OOM了.
朋友问下这个memoryCacheSize的设置是哪个类里面的方法啊,弄了半天没弄出来
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 9 楼 u014448521 的回复:
另外可以试试直接把data用inputstream保存在本地而不转为bitmap 到要用的时候在适当压缩从本地读出来 这样在本地保存的图片就不会被压缩
因为需求必须得先转为bitmap,因为下个界面就是图片预览与编辑
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 8 楼 heaimnmn 的回复:
建议直接调用源码中的方法,源码中拍照是没有压缩的,,,
这个怎么弄啊,我对拍照这一块的代码不是很了解
zyl9241 2015-01-09
  • 打赏
  • 举报
回复
另外可以试试直接把data用inputstream保存在本地而不转为bitmap 到要用的时候在适当压缩从本地读出来 这样在本地保存的图片就不会被压缩
哎,真难 2015-01-09
  • 打赏
  • 举报
回复
建议直接调用源码中的方法,源码中拍照是没有压缩的,,,
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 6 楼 dalor 的回复:
清晰高是追求的目标罢了,android不像ios,有很大的内在可控. 现在的android手机,高清的照相机,拍出来的照片都几M一张,android的内存,开发人员也不能随便控制.本身这是android的短板. 你再试试设置memoryCacheSize,把它设置大一些,但我觉得,不对图片进行压缩处理,这个问题还是不能解决,更何况,应用中图片显示和操作多的话,就更容易OOM了.
好的,我先试试
开发者_android 2015-01-09
  • 打赏
  • 举报
回复
引用 5 楼 xj396282771 的回复:
[quote=引用 1 楼 u014448521 的回复:] onPictureTaken()函数里面 bitmap = BitmapFactory.decodeByteArray(data, 0,data.length); 这里试试用Bitmap.Options压缩下
引用 3 楼 dalor 的回复:
之前打开的图片没有释放也是可能的. 不过,还得觉得,应该是相机拍照的图片太大直接导致. 在得到数据时,就先对图片进行压缩处理,再使用处理后的bitmap.
我之所以没有先用Bitmap.Options压缩,是因为我们老板要求拍出来得照片清晰度要高。请问还有别的解决方案么[/quote] 清晰高是追求的目标罢了,android不像ios,有很大的内在可控. 现在的android手机,高清的照相机,拍出来的照片都几M一张,android的内存,开发人员也不能随便控制.本身这是android的短板. 你再试试设置memoryCacheSize,把它设置大一些,但我觉得,不对图片进行压缩处理,这个问题还是不能解决,更何况,应用中图片显示和操作多的话,就更容易OOM了.
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 1 楼 u014448521 的回复:
onPictureTaken()函数里面 bitmap = BitmapFactory.decodeByteArray(data, 0,data.length); 这里试试用Bitmap.Options压缩下
引用 3 楼 dalor 的回复:
之前打开的图片没有释放也是可能的. 不过,还得觉得,应该是相机拍照的图片太大直接导致. 在得到数据时,就先对图片进行压缩处理,再使用处理后的bitmap.
我之所以没有先用Bitmap.Options压缩,是因为我们老板要求拍出来得照片清晰度要高。请问还有别的解决方案么
Jing丶無雙 2015-01-09
  • 打赏
  • 举报
回复
引用 2 楼 lxfhjjsfq 的回复:
我觉得你先把data.length打印出来看看。oom是解析图片出的问题,有可能是之前的图片太多没释放,也有可能解析数据本身太大。
01-09 16:37:45.415: D/解码(28946): data.length=972705
开发者_android 2015-01-09
  • 打赏
  • 举报
回复
之前打开的图片没有释放也是可能的. 不过,还得觉得,应该是相机拍照的图片太大直接导致. 在得到数据时,就先对图片进行压缩处理,再使用处理后的bitmap.
_xianfeng99 2015-01-09
  • 打赏
  • 举报
回复
我觉得你先把data.length打印出来看看。oom是解析图片出的问题,有可能是之前的图片太多没释放,也有可能解析数据本身太大。
zyl9241 2015-01-09
  • 打赏
  • 举报
回复
onPictureTaken()函数里面 bitmap = BitmapFactory.decodeByteArray(data, 0,data.length); 这里试试用Bitmap.Options压缩下

80,472

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧