0

在我的应用程序中,我有不同的列表视图,其中包含一些缩略图。今天我开始重构,我想实现 LRU 缓存。我正在遵循 Android 指南,但我想知道是否更好地为整个应用程序初始化一个 LRU 缓存,或者更好地为每个列表视图初始化 LRU 缓存。我害怕内存不足。因此,我有以下我自己无法回答的问题: - 一个用单例模式初始化的 LRU 缓存是个好主意吗?- 如果内存不足,是否会导致以下LRU Cache初始化的outOfMemory情况?

 @Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    // Get max available VM memory, exceeding this amount will throw an
    // OutOfMemory exception. Stored in kilobytes as LruCache takes an
    // int in its constructor.
    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

    // Use 1/8th of the available memory for this memory cache.
    final int cacheSize = maxMemory / 8;

    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
        @Override
        protected int sizeOf(String key, Bitmap bitmap) {
            // The cache size will be measured in kilobytes rather than
            // number of items.
            return bitmap.getByteCount() / 1024;
        }
    };
    ...
}
  • 如果内存不足,LRU缓存会自动释放吗?我想知道当我使用 LRU 缓存时应用程序是否会出现释放内存的问题(应用程序因内存不足而崩溃?)

  • 整个应用程序只有一个 LRU 缓存,会不会有问题?

  • 整个应用程序有多个 LRU 缓存,它们会是一个问题吗?
4

1 回答 1

1

我有很多问题,所以我可以在这里给你一些有用的答案。

如果内存不足,LRU缓存会自动释放吗?我想知道如果我使用 LRU 缓存,应用程序是否会出现释放内存的问题

LRU Cache不会自动释放内存。您将需要以编程方式驱逐条目。

整个应用程序只有一个 LRU 缓存,会不会有问题?

整个应用程序有多个 LRU 缓存,它们会是一个问题吗?

该类LruCache是一个泛型类,具有键的类型和值的类型。我会说您希望为要缓存的每种对象类型拥有一个 LRU 缓存。您正在做我所做的:缓存Bitmaps 并使用 s 键入String

只是一个旁注:小心使用bitmap.getByteCount(). JavaDocs 是这样说的:

从 KITKAT 开始,此方法的结果不能再用于确定位图的内存使用情况。见getAllocationByteCount()

我正在为 s 使用 LRU 缓存Bitmap。我认为只要调用此方法就足以覆盖Application.onTrimMemory()和清除缓存。

此外,我做了与您相同的事情,并根据应用程序可用的堆内存百分比设置缓存大小。

但是会发生这样的情况:当我的应用程序处于内存不足状态并且我的应用程序会尝试下载内存不足的图像时,GC 会运行,但BitmapFactory仍然无法为Bitmap. 日志显示该onTrimMemory()方法被异步调用,有时在OutOfMemoryError抛出后几乎整整一秒!

GOOGLE:如果系统不能告诉我我的内存不足,直到OutOfMemoryError被抛出,我到底应该如何管理我的内存?

疯狂。彻头彻尾的疯狂。

这就是我最终做的事情:我会捕获OutOfMemoryError一个 try 块,清除那里的缓存,然后重试对服务器的图像请求。他们告诉你不要做的确切的事情。但它最终解决了我的问题。该应用程序现在稳定了很多。

因此,在实现 LRU 缓存后,请确保对应用程序进行压力测试;尝试让它进入低内存情况并查看它的行为。对我来说,使用模拟器时效果最好。模拟器会有一个 96M 的小堆限制,但如果它有一个高屏幕分辨率,图像资源会缩放到相当大,这使得将内存推到最大值相当容易。

如果您正在显示缩略图,但您从服务器获取图像并且它们可能比您的大ImageView,请确保您阅读了这篇文章:有效加载大型位图 | Android 开发者学习如何在不浪费内存的情况下下载适当大小的位图。

您也可以尝试让系统进行缓存并设置一个HttpResponseCache.

无论你最终做什么,一定要给你的应用程序施加压力,看看它在没有多少堆剩余的情况下表现如何。

并准备好应对一点挫折。

于 2016-09-17T00:54:14.337 回答