Android:如何在运行时增加堆大小?
Posted
技术标签:
【中文标题】Android:如何在运行时增加堆大小?【英文标题】:Android: how to increase heap size at runtime? 【发布时间】:2011-05-06 09:16:13 【问题描述】:我的应用程序中有一个使用 SoftReferences 实现的图像缓存。 Dalvik 使用相对较小的堆启动应用程序,然后在需要时增加它。但我想从一开始就让我的堆大小更大。那是因为当我在缓存中已经有一些图像,并且活动开始(例如)或发生其他峰值内存需求时,我的缓存被清除以让内存满足该峰值需求。结果,高峰期过去后,我还有 2-3 MB 的可用空间,但我的缓存是空的!
我看到的解决这个问题的方法是预先分配一个更大的堆正手,所以即使峰值消耗 2-3 MB,它仍然有一些空间空间,所以我的 SoftReferences 不会被清除。
我发现VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE)
会很有帮助。特别是,谷歌在他们的应用程序中使用了它,正如提到的here。但是,VMRuntime 类被标记为已弃用,并表示将在未来版本中从公共 API 中删除。所以setMinimumHeapSize
不是永久的解决方案。
我如何让 Dalvik 在启动时增加我的堆?
目前我通过分配一个大数组并释放它来使用一种非常直接和俗气的技术。这使得 Dalvik 可以随心所欲地增长堆。但是,我确信必须有更优雅的方式来做到这一点。请告诉我好吗?
【问题讨论】:
我怀疑你会找到使用公共 API 的方法 google maps 使用反射和这个 api,我在搜索有关通话的信息时发现了这篇文章 :) 【参考方案1】:您可以做一些更好的事情,而不是增加堆大小。正如您所说,您正在使用 SoftReferences 实现的应用程序中维护缓存。最好的办法是使用 LruCache 你可以这样做:
private LruCache<String, Bitmap> bitmapCache;
final int memClass;
int cacheSize;
memClass = ((ActivityManager) context.getSystemService(
Context.ACTIVITY_SERVICE)).getMemoryClass();
返回当前设备的每个应用程序的近似内存类。这让您了解应该对应用程序施加多硬的内存限制以使整个系统发挥最佳作用。返回值以兆字节为单位;基准 android 内存类是 16(恰好是这些设备的 Java 堆限制);某些具有更多内存的设备可能会返回 24 甚至更高的数字。
cacheSize = 1024 * 1024 * memClass / 10;
bitmapCache = new LruCache<String, Bitmap>(cacheSize)
@Override
protected int sizeOf(String key, Bitmap value)
return value.getHeight() * value.getRowBytes();
;
如果内存超过 LruCache 的定位内存,它将从 LruCache 中删除位图图像,并在其中加载新图像。
【讨论】:
【参考方案2】:如果缓存通常如您所说的那样小,您可以自行决定应用程序的有效占用空间,并在没有 SoftReferences 的情况下维护自己的缓存。
例如通过一个简单的总字节计数器:只需添加或移动任何用于列表顶部的元素,如果它是新的,则将其大小添加到计数器中。如果总字节数超过您的经验限制,则从底部删除,从而减少您的计数器。也许LinkedHashMap
类对此很有用:它可以像HashMap
一样用作缓存,但它也有像列表一样的顺序。
【讨论】:
【参考方案3】:问题在于,SoftReferences 对于在 java 堆空间中完成的分配很有用,但图像是本地分配的,所以这种缓存类型在 Android 上并不适用。
【讨论】:
实际上,我将图像作为字节数组存储在缓存中,因为它们是从服务器接收的(缓存处于连接级别)。但无论如何,这是一个有用的提示 - 谢谢! 这是一个老话题,但我还是会回复的。就我而言,在任何给定时刻,从服务器获取的所有图像中只有一小部分会显示出来。所以没有双 RAM 的使用。事实上,我们使用 2 级缓存,第一级在磁盘上,第二级在内存中较小。我的问题是关于优化内存的。我看到了我的错:我应该以更抽象的方式问我的问题;我不应该谈论服务器和图像,因为这会让人们陷入困境。【参考方案4】:您不能动态增加堆大小。
您可以通过在清单中使用 android:largeHeap="true" 来请求使用更多,但您可能不会获得比正常更多的堆大小,因为这只是一个请求。
此外,您可以使用本机内存,因此您实际上绕过了堆大小限制。
这里有一些关于它的帖子:
How to cache bitmaps into native memory
JNI bitmap operations , for helping to avoid OOM when using large images
这是我为它制作的一个库:
https://github.com/AndroidDeveloperLB/AndroidJniBitmapOperations【讨论】:
【参考方案5】:我认为您不能或不应该在这个级别影响设备的内存。让系统做它的事,不要违背它。即使在活动开始时,您是否也需要使用 SoftReferences 保存这么大的图像缓存?
你想检查它是如何在 Shelves 中完成的:参见 http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/util/ImageUtilities.java?r=26 中的第 82 行
【讨论】:
我从来没有说过我的缓存很大。事实上,它不依赖于缓存大小——即使是小的缓存它也不会工作,正如我所说的,因为那些内存激增。我拥有约 100 个项目的缓存,每个项目 2-3KB - 这不是一个巨大的缓存,但它仍然每次都会被清除。我发现某些 Android 版本中的垃圾收集器存在 SoftReferences 的错误:***.com/questions/4014033 这使得基于 SoftReference 的缓存实际上毫无用处。以上是关于Android:如何在运行时增加堆大小?的主要内容,如果未能解决你的问题,请参考以下文章