2012-02-14 17 views
18

AndroidアプリケーションのビットマップにGoogle Guava LoadingCacheを読み込みます。アプリケーションでは、キャッシュのビットマップをキャンバスにペイントする描画スレッドを実行しています。特定のビットマップがキャッシュにない場合は、描画されず、読み込みスレッドがブロックスレッドをブロックすることはありません。AndroidでGuavaキャッシュのパフォーマンスが悪い

しかし、ペインティングでは視覚的な吃音が発生し、1秒あたりのフレームレートはどのようにして欲しいのですか?私はそれをキャッシュのgetIfPresent()メソッドに釘付けにしました。それだけで、アプリケーションの総CPU時間の20%以上を占めます。これは、すでに存在しているビットマップの唯一のルックアップで、心の中で

profiling-guava-cache.jpg

ベア:getIfPresent()LocalCache$Segment.get()は、時間の80%以上を要します。 get()に負荷が発生することはありません。私は、セグメントが一杯になった場合にどの退去が起こるかを決定するLRUキューについて、簿記オーバーヘッドがget()にあると考えました。しかし、これは少なくともKey-LookupLRU-LinkedHashmap.get()で私に与えられるものよりも遅いものです。

ルックアップが遅い場合、要素がキャッシュ内にある場合、高速ルックアップを取得するためにキャッシュを使用します。キャッシュにはポイントがありません。私もgetAllPresent(a)asMap()を試しましたが、同等の性能を発揮します。

ライブラリのバージョンは次のとおりです。グアバ-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は以下のとおりです。そのミスカウントがbasicly HITCOUNT刻みと同じまま

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

後。この場合、キャッシュは負荷がまばらに発生するのに十分ですが、getIfPresentは遅いです。

+1

他のフレーズを太字にしないでください。私はそれを取り出すために編集を提出したので、読むのは難しいです。 – simchona

+0

ありがとう、それをより読みやすくするための編集のためのsimchona。 – user643011

+0

'tiles.cacheStats()'の結果を投稿できますか? –

答えて

30

CacheBuilderは、並行処理が主な関心事であったサーバー側のキャッシュ用に設計されています。したがって、より良いマルチスレッド動作と引き換えに、シングルスレッドとメモリのオーバーヘッドを排除します。 Android開発者は、LruCache,LinkedHashMap、またはシングルスレッドのパフォーマンスとメモリが主な懸念事項となるようなものを使用する必要があります。将来、軽量の非並行キャッシュが必要であることを示すためにconcurrencyLevel = 0が存在する可能性があります。

+1

私はconcurrencyLevel = 1を試みましたが、アクセス時間は改善されませんでした。 concurrencyLevel = 0はエラーにつながります。実際、AtomicReferenceArrayはかなりのCPU時間を要します。私は今、android.util.LruCacheに行くつもりです。 ARMアーキテクチャと冗長な答えに関するご意見ありがとうございます。私は、今後concurrencyLevel = 0を見たいと思っています。 – user643011

+1

concurrencyLevel = 1は、単一のライター、複数のリーダーを意味します。これは、作業の簡素化の大部分を提供するものではありません。 0のレベルは、読者が書込みと同期されていることを示すので、同期バージョンを実装することができます。私がレビューしたLruCacheをコード化するとき、私たちはまだキャッシュインターフェースで作業していたので、MapMakerにconcurrencyLevel = 0を追加することは優先順位が低くなりました。こうしてLruCacheは生まれました。 –

+4

FYI、LruCacheは、互換性ライブラリのpre-Honeycombでも利用できます。 http://developer.android.com/sdk/compatibility-library.html –

2

Androidコードは、常にJVM内と同じ方法で最適化されているとは限りません。 JavaでうまくいくのはAndroidでもうまくいかないかもしれません。あなた自身の非常にシンプルなキャッシュを書くことをお勧めします。例えばLinkedHashMap.removeEldestEntry()を使用して、それがどうなるかを見てください。

関連する問題