一尘不染

Android上的Guava Cache性能不佳

javascript

我们在Android应用程序中将加载的Google GuavaLoadingCache用于位图。在应用程序中,我正在运行一个绘图线程,该线程将缓存中的位图绘制到画布上。如果特定的位图不在缓存中,则不会绘制该位图,因此不会有任何加载阻塞图线程。

但是,绘画会导致视觉卡顿,每秒帧数并不是我们想要的。我将其固定getIfPresent()在缓存的方法上。仅此一项就占用了应用程序总CPU时间的20%以上。在getIfPresent() LocalCache$Segment.get()需要的时间超过80%:

profiling-guava-cache.png

请记住,这只是对已经存在的位图的查找。永远不会发生负载get()。我认为get()LRU队列会产生簿记开销,该开销决定了该段是否已满时发生哪个逐出。但这至少比a Key-Lookupin LRU-LinkedHashmap.get()给我的速度慢一个数量级。

如果元素在缓存中,我们将使用缓存来进行快速查找;如果查找速度较慢,则对其进行缓存是没有意义的。我也尝试过getAllPresent(a),asMap()但是它给出了相同的性能。

库版本为:guava-11.0.1.jar

LoadingCache的定义如下:

LoadingCache<TileKey, Bitmap> tiles = CacheBuilder.newBuilder().maximumSize(100).build(new CacheLoader<TileKey,Bitmap>() {
            @Override
            public Bitmap load(TileKey tileKey) {
            System.out.println("Loading in " + Thread.currentThread().getName() + " "
                + tileKey.x + "-" + tileKey.y);

            final File[][] tileFiles = surfaceState.mapFile.getBuilding()
                .getFloors().get(tileKey.floorid)
                .getBackground(tileKey.zoomid).getTileFiles();
            String tilePath = tileFiles[tileKey.y][tileKey.x].getAbsolutePath();

            Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;

            return BitmapFactory.decodeFile(tilePath, options);
            }
        });

我的问题是:

我会用错吗?
Android的实现无法实现吗?
我错过了配置选项吗?
这是正在处理的缓存的已知问题吗?
更新:

绘制约100帧后,CacheStats为:

I/System.out( 6989): CacheStats{hitCount=11992, missCount=97,
loadSuccessCount=77, loadExceptionCount=0, totalLoadTime=1402984624, evictionCount=0}

之后,missCount基本上与hitCount增量相同。在这种情况下,缓存足够大,无法进行稀疏的加载,但是getIfPresent仍然很慢。


阅读 409

收藏
2020-09-23

共1个答案

一尘不染

CacheBuilder是为服务器端缓存而设计的,而并发是首要考虑因素。因此,它需要权衡单线程和内存开销,以换取更好的多线程行为。Android开发应该使用LruCache,LinkedHashMap`或类似的地方单线程性能和存储器成为主要关注。将来可能会出现concurrencyLevel = 0,以指示需要轻量级的非并行缓存。

2020-09-23