Android上的Guava Cache性能不佳

use*_*011 19 java android guava

我们在Android应用程序中使用加载Google Guava LoadingCache作为位图.在应用程序中,我正在运行一个绘图线程,它将缓存中的位图绘制到Canvas.如果特定位图不在缓存中,则不会绘制它,因此任何加载都不会阻止绘制线程.

然而,这种绘画导致视觉口吃,每秒帧速率不是我们想要的.我把它钉getIfPresent()在了缓存的方法上.仅此一项占应用总CPU时间的20%.在getIfPresent() LocalCache$Segment.get()需要的时间超过80%:

分析-番石榴cache.jpg

请记住,这只是一个已经存在的位图的查找.永远不会发生负担get().我认为get()LRU队列会有一个簿记开销,它决定了如果段已满就会发生哪些驱逐.但是,这是至少一个数量多么慢的顺序Key-LookupLRU-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);
            }
        });
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  • 我用错了吗?
  • 它的实现是否适用于Android?
  • 我错过了配置选项吗?
  • 这是正在处理的Cache的已知问题吗?

更新:

在绘制大约100帧后,CacheStats是:

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

之后,missCount基本上与hitCount增量保持一致.在这种情况下,缓存足够大,以便负载稀疏地发生,但getIfPresent仍然很慢.

Ben*_*nes 31

CacheBuilder是为服务器端缓存而设计的,其中并发性是主要关注点.因此,它会牺牲单线程和内存开销来换取更好的多线程行为.Android开发人员应该使用LruCache,LinkedHashMap或类似的单线程性能和内存是主要问题.将来可能会有concurrencyLevel = 0来指示需要轻量级,非并发缓存.

  • 仅供参考,LruCache也可在兼容性库中的Honeycomb之前使用.http://developer.android.com/sdk/compatibility-library.html (4认同)
  • concurrencyLevel=1 表示单个写入者,多个读取者。这并没有提供太多的工作简化。级别 0 表示读取器与写入同步,因此可以实现同步版本。当我对 LruCache 进行代码审查时,我们仍在处理 Cache 接口,因此向 MapMaker 添加 concurrencyLevel=0 的优先级较低。于是LruCache诞生了。 (2认同)