Android:如何在运行时增加堆大小?
我的应用程序中有一个图像缓存,它是使用 SoftReferences 实现的。 Dalvik 以相对较小的堆启动应用程序,然后在需要时增加它。但我希望从一开始就增大堆大小。这是因为,当我的缓存中已经有一些图像,并且活动开始(例如)或出现其他峰值内存需求时,我的缓存将被清除,以便让内存满足该峰值需求。结果,峰值过去后,我仍然有 2-3 MB 的可用空间,但我的缓存是空的!
我看到的解决这个问题的解决方案是预先分配一个更大的堆,因此即使峰值消耗为 2-3 MB,它仍然有一些空间,因此我的软引用不会被清除。
我发现 VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE)
会很有帮助。特别是,谷歌在他们的应用程序中使用了它,如上所述 此处。但是, VMRuntime 类已被标记为已弃用,据说已从未来版本中的公共 API。所以 setMinimumHeapSize
并不是一个永久的解决方案。
那么我如何让 Dalvik 在启动时增加我的堆?
目前,我使用一种非常简单且俗气的技术,只需分配一个大数组并释放它。这使得 Dalvik 按照我的意愿增长堆。但是,我确信一定有更优雅的方法来做到这一点。你能告诉我吗?
I have an image cache in my application which is implemented using SoftReferences. Dalvik starts applications with relatively small heap, and then increases it in case of demand. But I'd like to have my heap size bigger from the beginning. That is because when I already have some images in the cache, and an activity starts (for example) or other peak memory demand occurs, my cache gets purged in order to let memory for that peak demand. As a result, after the peak is gone I still have 2-3 MB of free space but my cache is empty!
The solution I see for this trouble is pre-allocating a bigger heap forehand so even with the peak consumption of 2-3 MBs it still has some roomspace so my SoftReferences are not purged.
I found that VMRuntime.getRuntime().setMinimumHeapSize(BIGGER_SIZE)
would be helpful. In particular, Google uses that in their apps, as mentioned here. However, VMRuntime class is marked deprecated and said to be removed from the public API in a future release. So setMinimumHeapSize
is not a permanent solution.
How then I make Dalvik to grow my heap at startup?
Currently I use a really straight-forward and cheesy technique by just allocating a large array and releasing it. This makes Dalvik grow the heap as I want. However, I'm sure there must be more elegant way of doing that. Could you tell me that, please?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以做一些更好的事情,而不是增加堆大小。正如您所说,您正在使用软引用实现的应用程序中维护缓存。最好的事情是使用 LruCache,你可以做这样的事情:
返回当前设备的大致每个应用程序内存类别。这让您了解应该对应用程序施加多大的内存限制,以使整个系统发挥最佳性能。返回值以兆字节为单位;基准 Android 内存类别是 16(这恰好是这些设备的 Java 堆限制);某些具有更多内存的设备可能会返回 24 甚至更高的数字。
如果内存超出了 LruCache 所定位的内存,它将从 LruCache 中删除位图图像,并将新图像加载到其中。
Instead of increasing heap size you can do some thing better. As you said that you are maintaining cache in you application which is implemented using SoftReferences. The best thing is to use LruCache you can do some thing like this:
Return the approximate per-application memory class of the current device. This gives you an idea of how hard a memory limit you should impose on your application to let the overall system work best. The returned value is in megabytes; the baseline Android memory class is 16 (which happens to be the Java heap limit of those devices); some device with more memory may return 24 or even higher numbers.
it will remove the bitmap images from LruCache if the memory exceeds the located memory to LruCache and load the new image in it.
如果缓存通常很小,正如您所说,您可以自己决定应用程序的有效占用空间,并在没有软引用的情况下维护自己的缓存。
例如,通过一个简单的总字节计数器:只需将使用的任何元素添加或移动到列表顶部,如果是新的,则将其大小添加到计数器中。如果总字节数超过您的经验法则限制,请从底部删除,从而减少计数器。也许 LinkedHashMap 类对此很有用:它可以像 HashMap 一样用作缓存,但它也有像列表一样的顺序。
If the cache is ususally small as you say, you can decide a valid footprint of your app by yourself and maintain your own cache without SoftReferences.
For example by a simple total byte counter: Just add or move any element used to the top of a list, add its size to the counter if it is new. Delete from the bottom if the total bytes exceed your rule-of-thumb limit, thereby decreasing your counter. Maybe the
LinkedHashMap
class is useful for that: It can be used as a cache like aHashMap
, but it has an order too like a list.问题是 SoftReferences 对于在 java 堆空间中完成的分配很有用,但图像是本地分配的,因此这种缓存类型在 Android 上实际上不起作用。
The problem is that SoftReferences are useful for allocations done in the java heap space, but images are allocated natively, so this cache type won't really work on Android.
您无法动态增加堆大小。
您可以通过在清单中使用 android:largeHeap="true" 来请求使用更多堆大小,但您可能不会获得比正常情况更多的堆大小,因为这只是一个请求。
另外,您可以使用本机内存,因此您实际上绕过了堆大小限制。
以下是我就此发表的一些帖子:
如何缓存位图到本机内存中
JNI位图操作,用于在使用大图像时帮助避免 OOM
,这是我为其制作的库:
you can't increase the heap size dynamically.
you can request to use more by using android:largeHeap="true" in the manifest, but you might not get any more heap size than normal, since it's only a request.
also, you can use native memory, so you actually bypass the heap size limitation.
here are some posts i've made about it:
How to cache bitmaps into native memory
JNI bitmap operations , for helping to avoid OOM when using large images
and here's a library i've made for it:
我认为你不能或不应该在这个级别影响设备的内存。让系统做它该做的事,不要违背它。即使活动开始,您是否也需要使用 SoftReferences 保存如此大的图像缓存?
您想检查 Shelves 中的操作方式:请参阅 http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/ util/ImageUtilities.java?r=26
I don't think you can or are supposed to influence a device's memory at this level. Let the system do its thing and don't go against it. Do you need to hold such a big image cache with SoftReferences even when activities start?
You want to check how it is done in Shelves: see line 82 in http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/util/ImageUtilities.java?r=26