我们在Android应用程序中将加载的Google GuavaLoadingCache用于位图。在应用程序中,我正在运行一个绘图线程,该线程将缓存中的位图绘制到画布上。如果特定的位图不在缓存中,则不会绘制该位图,因此不会有任何加载阻塞图线程。
但是,绘画会导致视觉卡顿,每秒帧数并不是我们想要的。我将其固定getIfPresent()在缓存的方法上。仅此一项就占用了应用程序总CPU时间的20%以上。在getIfPresent() LocalCache$Segment.get()需要的时间超过80%:
请记住,这只是对已经存在的位图的查找。永远不会发生负载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仍然很慢。
CacheBuilder是为服务器端缓存而设计的,而并发是首要考虑因素。因此,它需要权衡单线程和内存开销,以换取更好的多线程行为。Android开发应该使用LruCache,LinkedHashMap`或类似的地方单线程性能和存储器成为主要关注。将来可能会出现concurrencyLevel = 0,以指示需要轻量级的非并行缓存。
CacheBuilder是为服务器端缓存而设计的,而并发是首要考虑因素。因此,它需要权衡单线程和内存开销,以换取更好的多线程行为。Android开发应该使用LruCache,