Android图片处理内存溢出学习

最近遇到一个问题,在Android机器上,调用自带的相机拍摄后获得相处,并且对获得的相片进行缩放,旋转,截取等操作,看似很简单,但是却遇到了一个,让人心疼的问题,我这里用五能手机进行测试,当然,功能测试是没有问题,当发给客户去测试的时候,却出现了内存溢出,哎无言啊...

原来他用的是三星的G3手机进行测试的,我们没有这款手机,后来借别人的G3手机测试,果然也出现这个问题:

java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:518)
at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:535)
at com.yippeearts.flashcards.CameraPage$1.onPictureTaken(CameraPage.java:73)
at android.hardware.Camera$EventHandler.handleMessage(Camera.java:734)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4514)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760)
at dalvik.system.NativeStart.main(Native Method)

这个在不同的手机上出现这种错误还是有点尴尬的。一直以为是对图片的逻辑处理出了什么问题,经过总结发现,估计是因为G3手机拍摄相片分辨率过高,使图片过大,造成过程中内存溢出,通过网上搜索若干解决加载大图片时内存溢出的问题:

尽量不要使用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、模拟器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();

2、优化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堆内存也可自己定义大小

对于一些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);

在图片处理的时候,确保图片引用及时回收。
发布了184 篇原创文章 · 获赞 46 · 访问量 182万+
展开阅读全文

当向Bitmap对象加载图片时,出现奇怪内存不够问题。

09-14

我不确定从哪开始解释这个问题。 在每一行,我有一个带着一对图片按钮的列表视图。当你点击列表行,它加载一个新的控件。因为照相机布局的问题我不得不建立我新的tab。这个控件加载完成的结果是一个地图。如果我点击我的按钮来加载图片预览(从SD卡加载一个图片)应用程序从这个控件返回到列表视图控件,导致结果处理器重新加载我的新的控件,那个不过就是一个图像的小部件。 所以这就是问题,图片显示在列表视图的时候都是带着光标和列表转换器的。这使得它相当的简单,但是我不确定我怎么能够调整大小(IE下有一点小,但是不是像素的关心)图片作为图片按钮的源文件在起作用。所以我只是调整了来自于手机、相机的照片的大小。 这个问题就是当它试图返回重新加载第二个控件的时候出现了内存不足的问题。 我的问题:是否有方法让我可以逐行创建列表转换器,那样我可以调整在运行中的图片的大小(按位)?这将是合适的,因为我还需要给每一行的小工具/元素做一些属性的改变,为了我不能在触摸屏的编辑选择有焦点的一行(我可以使用滚动条)。 我知道我可以做一个不同频道信号传输来改变图片大小,并保存我的图片,但是这真的不是我想要做的,但是如果你能够给一些建议的示例代码那将是很好的。 我是这样做的 String[] from = new String[] { DBHelper.KEY_BUSINESSNAME, DBHelper.KEY_ADDRESS, DBHelper.KEY_CITY, DBHelper.KEY_GPSLONG, DBHelper.KEY_GPSLAT, DBHelper.KEY_IMAGEFILENAME + ""}; to = new int[] { R.id.businessname, R.id.address, R.id.city, R.id.gpslong, R.id.gpslat, R.id.imagefilename }; notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to); setListAdapter(notes); Where R.id.imagefilename is a ButtonImage R.id.imagefilename是一个按钮图片 这是我的日志 09-13 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process. 09-13 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes 09-13 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.resolveUri(ImageView.java:484) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.setImageURI(ImageView.java:281) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.CursorAdapter.getView(CursorAdapter.java:150) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.obtainView(AbsListView.java:1057) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.makeAndAddView(ListView.java:1616) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.fillSpecific(ListView.java:1177) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.layoutChildren(ListView.java:1454) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.onLayout(AbsListView.java:937) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:922) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:920) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.performTraversals(ViewRoot.java:771) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.handleMessage(ViewRoot.java:1103) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Handler.dispatchMessage(Handler.java:88) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Looper.loop(Looper.java:123) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at android.app.ActivityThread.main(ActivityThread.java:3742) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invokeNative(Native Method) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invoke(Method.java:515) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497) 09-13 05:05:49.917: ERROR/AndroidRuntime(3896): at dalvik.system.NativeStart.main(Native Method) 09-13 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed 当显示一个图片的时候我又有了一个新问题 09-13 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d 09-13 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri: 09-13 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process. 09-13 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes 09-13 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览