标题
[android]android largeHeap 解决大图片加载 Throwing OutOfMemoryError 错误
clq
浏览(473) +
2022-01-19 14:44:29 发表
编辑
关键字:
[2022-01-20 09:01:11 最后更新]
[android]android largeHeap 解决大图片加载 Throwing OutOfMemoryError 错误 android:largeHeap="true" 解决大图处加载 “Throwing OutOfMemoryError "Failed to allocate a 8388464 byte allocation with 3689696 free bytes and 3MB until OOM" 错误。 参考 https://blog.csdn.net/mp624183768/article/details/79209751 https://zhuanlan.zhihu.com/p/25186586
clq
2022-01-19 14:45:00 发表
编辑
android:largeHeap="true"的作用 安果移不动 于 2018-01-30 19:26:58 发布 1071 收藏 分类专栏: # 进阶的api 版权 进阶的api 专栏收录该内容 15 篇文章 0 订阅 订阅专栏 AndroidManifest.xml文件中可以设置 android:largeHeap="true" 我使用的测试设备为Nexus5 系统为5.0 安卓设备对应用内存的限制,一般在/system/build.prop文件中可以查看到 dalvik.vm.heapsize=512m(最大内存限制) dalvik.vm.heapgrowthlimit=192m(普通内存限制) 当设置为android:largeHeap="true" 时 内存溢出 03-03 15:21:51.480: I/art(11679): Clamp target GC heap from 513MB to 512MB 当设置为android:largeHeap="false" 时 内存溢出 03-03 15:29:00.711: I/art(14283): Clamp target GC heap from 205MB to 192MB 测试方法为不断的加载图片到内存,比如 Bitmap bitmap[] = new Bitmap[300]; for (int i=0; i bitmap[i] = BitmapFactory.decodeResource(getResources(), R.drawable.eee); } 获得最大内存限制: android3.0及以上可调用此方法 ((ActivityManager)getSystemService(Context.ACTIVITY_SERVICE)).getLargeMemoryClass(); ———————————————— 版权声明:本文为CSDN博主「安果移不动」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/mp624183768/article/details/79209751
clq
2022-01-19 14:45:48 发表
编辑
探究android:largeHeap 技术小黑屋 技术小黑屋 http://droidyue.com/ 在日常的Android开发中,我们必然遇到过OutOfMemoryError这样的崩溃,产生的原因无外乎两点,一是内存过小不够用,二是程序设计有误,导致不能释放内存,其中后者情况较多。在解决这个问题时,我们亦或多或少听到android:largeHeap,然而这个概念又是什么呢,它该如何使用,存在哪些问题呢。本文讲比较全面介绍Android中的largeHeap帮助各位全面深入了解这个概念。 磨刀不误砍柴工 为了便于理解,先简单介绍一些和文章相关的基础概念。 通常,一个Android程序在运行时会启动一个Dalvik虚拟机(暂不讨论ART模式)虚拟机的运行时内存一般由堆和栈两大部分构成。栈是存储方法调用的一片内存数据区。堆内存占据了虚拟机的大部分内存空间,程序执行时产生的对象就分配在堆内存上。如果是堆内存没有可用的空间存储生成的对象,JVM会抛出java.lang.OutOfMemoryError。 如若具体了解堆和栈,请参考文章Java中的堆和栈的区别和JVM运行时的数据区 largeHeap介绍 一个应用如果使用了largeHeap,会请求系统为Dalvik虚拟机分配更大的内存空间。使用起来也很方便,只需在manifest文件application节点加入android:largeHeap=“true”即可。 android:allowBackup="false" android:label="@string/app_name" android:debuggable="true" android:theme="@android:style/Theme.Black" android:largeHeap="true" > largeHeap有多大 在Android中,有如下两个方法可以帮助我们查看当前内存大小 ActivityManager.getMemoryClass()获得内用正常情况下内存的大小ActivityManager.getLargeMemoryClass()可以获得开启largeHeap最大的内存大小 然而largeHeap这个最大值是如何决定的呢?想要了解这个问题,我们就需要看一下Android系统中的一个文件。 这个文件路径是/system/build.prop,由于文件比较大,这里我们只截取关于dalvik内存的配置信息,如下。 dalvik.vm.heapstartsize=8m dalvik.vm.heapgrowthlimit=192m dalvik.vm.heapsize=512m dalvik.vm.heaptargetutilization=0.75 dalvik.vm.heapminfree=2m dalvik.vm.heapmaxfree=8m 上面有诸多配置,但从字面意思也不难理解,为了正确理解,有必要逐一解释一下。 dalvik.vm.heapstartsize=8m 相当于虚拟机的 -Xms配置,该项用来设置堆内存的初始大小。 dalvik.vm.heapgrowthlimit=192m 相当于虚拟机的 -XX:HeapGrowthLimit配置,该项用来设置一个标准的应用的最大堆内存大小。一个标准的应用就是没有使用android:largeHeap的应用。 dalvik.vm.heapsize=512m 相当于虚拟机的 -Xmx配置,该项设置了使用android:largeHeap的应用的最大堆内存大小。 dalvik.vm.heaptargetutilization=0.75 相当于虚拟机的 -XX:HeapTargetUtilization,该项用来设置当前理想的堆内存利用率。其取值位于0与1之间。当GC进行完垃圾回收之后,Dalvik的堆内存会进行相应的调整,通常结果是当前存活的对象的大小与堆内存大小做除法,得到的值为这个选项的设置,即这里的0.75。注意,这只是一个参考值,Dalvik虚拟机也可以忽略此设置。 dalvik.vm.heapminfree=2m与dalvik.vm.heapmaxfree=8m dalvik.vm.heapminfree对应的是-XX:HeapMinFree配置,用来设置单次堆内存调整的最小值。dalvik.vm.heapmaxfree对应的是-XX:HeapMaxFree配置,用来设置单次堆内存调整的最大值。通常情况下,还需要结合上面的 -XX:HeapTargetUtilization的值,才能确定内存调整时,需要调整的大小。 largeHeap需要权限么 为何有此疑问呢? 原因是这样的。 首先一个设备的内存是固定的,当我们使用了largeHeap之后就可以使我们的程序内存增加,但这部分增加的内存有可能是源自被系统杀掉的后台程序。所以,使用largeHeap理论上是有可能杀掉其他的程序的。 然而,结果就是不需要权限,Google在一开始就是这样,只需要简单在Application元素上加入android:largeHeap=“true”就能正常使用。 largeHeap对GC的影响 拥有了更多的内存,是不是就意味着要花更多的时间遍历对象垃圾回收呢?其实不然。 首先largeHeap自Android 4.0开始支持,而并发的垃圾回收方式从Android 2.3开始引入。 在引入并发垃圾回收之前,系统采用了Stop-the-World回收方式,进行一次垃圾回收通常消耗几百毫秒,这是很影响交互和响应的。 引入并发垃圾回收之后,在GC开始和结束的阶段会有短暂的暂停时间,通常在10毫秒以内。 因此在支持largeHeap的系统上都采用了并发垃圾回收,GC的Pause Time不会很长,对交互响应影响甚微。 慎用largeHeap 对于largeHeap的使用,我们该持有的谨慎的态度,largeHeap可以使用,但是要谨慎。 对于本身对内存要求过大的图片或者视频应用,我们可以使用largeHeap。 除上面的情况,如果仅仅是为了解决OutOfMemoryError这样的问题,而尝试使用largeHeap分配更大内存的这种指标不治本的方法不可取。对待这样的OOM问题,建议阅读以下几篇文章,了解Android中内存泄露和垃圾回收,从代码上去查找问题,从根本上解决问题。 补漏 无论是否开启largeHeap,ActivityManager.getLargeMemoryClass()都可以打印出largeHeap的大小。因为其本身只是读取了配置文件的值而已。即下面的代码无论largeHeap开启与否,打印出来的日志都相同 ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); int largeMemoryClass = activityManager.getLargeMemoryClass(); int memoryClass = activityManager.getMemoryClass(); ActivityManager.MemoryInfo info = new ActivityManager.MemoryInfo(); activityManager.getMemoryInfo(info); Log.d(LOGTAG, "largeMemoryClass = " + largeMemoryClass); Log.d(LOGTAG, "memoryClass = " + memoryClass); 如何验证 关于如何验证,这里设置一个按钮,每次创建100M的内存对象,观察开启largeHeap前后的反应 private ArrayList mLeakyContainer = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.testBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { byte[] b = new byte[100 * 1000 * 1000]; mLeakyContainer.add(b); } }); testMemoryInfo(); } 以正常情况下可用192M内存为例,点击两次按钮,应用崩溃。然后在manifest开启largeHeap,以最大512M内存可用为例,点击6次应用崩溃 验证源码可以访问github查看largeHeapDemo 推荐扩展文章 Android中Handler引起的内存泄露避免Android中Context引起的内存泄露Google IO:Android内存管理主题演讲记录
clq
2022-01-20 09:01:11 发表
编辑
https://blog.csdn.net/Caster_Saber/article/details/52494984 https://blog.csdn.net/u012301841/article/details/50493214 Android 图片处理以及recycle机制 我们经常会涉及到对相机拍照,然后处理拍照后的图片,最后在显示到UI上。如果处理的不好,就会导致系统卡顿,甚至会出现OOM,程序崩溃。 图片的处理 public static BitmapDrawable getScaledDrawable(Activity a, String path) { if (a == null) return null; Display display = a.getWindowManager().getDefaultDisplay(); int destWidth = display.getWidth(); int destHeight = display.getHeight(); // Read in the dimensions of the image on disk BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(path, options); int srcHeight = options.outHeight; int srcWidth = options.outWidth; int inSampleSize = 1; if (srcHeight > destHeight || srcWidth > destWidth) { if (srcWidth > srcHeight) { inSampleSize = Math.round(srcHeight / destHeight); } else { inSampleSize = Math.round(srcWidth / destWidth); } } options = new BitmapFactory.Options(); options.inSampleSize = inSampleSize; Bitmap bitmap = BitmapFactory.decodeFile(path, options); return new BitmapDrawable(a.getResources(), bitmap); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 图片的回收 public static void cleanImageView (ImageView imageView) { if (!(imageView.getDrawable() instanceof BitmapDrawable)) return; // clean uo the view's image for the sake of memory BitmapDrawable b = (BitmapDrawable) imageView.getDrawable(); b.getBitmap().recycle(); imageView.setImageDrawable(null); } 1 2 3 4 5 6 7 8 9 Bitmap.recycle() 方法的调用需要一些解释。Android开发文档暗示不需要调用Bitmap.recycle()方法,但实际上需要。 Bitmap.recycle()方法释放了Bitmap占用的原始存储空间。这也是Bitmap对象最核心的部分,这取决于具体的安卓版本,原始存储空间可大可小,在Honeycomb之前,它存储了Java Bitmap的所有数据。 如果不主动调用recycle()方法释放内存,占用的存储空间也会被清理。但是,它是在将来的某个时间点在finalizer中清理,而不是在Bitmap自身的垃圾回收中清理。这意味着很可能在finalizer调用之前,应用已经耗尽内存资源了。 finalizer的执行有时不太靠谱,且这类bug很难追踪和重现。因此,如果应用使用的图片文件很大,最好主动调用recycle()方法,以避免可能的内存耗尽问题。 在onStart() 方法中加载图片,在onStop()方法中移除图片是一种好的习惯。这些方法标志着用户可以看到Activity的时间点。
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.