title: Bad performance with Guava Cache on Android
body: <p>We use a loading Google Guava LoadingCache for bitmaps in an Android application. In the application I am running a drawing Thread, that paints the bitmaps in the cache to a Canvas. If a specific bitmap is not in the cache, it does not get drawn so that no loading will ever block the drawing Thread.</p>
  <p>However, the painting results in visual stuttering and the frames per second rate is not how we would like it. I nailed it down to the <code>getIfPresent()</code> method of the cache. That alone takes over 20% of the applications total CPU time. In <code>getIfPresent()</code> <code>LocalCache$Segment.get()</code> takes over 80% of the time:</p>
  <p><img src="https://www.dropbox.com/s/feexiwdb8aeowvl/profiling-guava-cache.png?dl=1" alt="profiling-guava-cache.jpg" /></p>
  <p>Bear in mind, this is only a lookup of an already present bitmap. There will never happen a load in <code>get()</code>.  I figured there would be a bookkeeping overhead in <code>get()</code> for the LRU queue that decides which eviction takes place if the segment is full. But this is at least an order of magnitude slower of what a <code>Key-Lookup</code> in <code>LRU-LinkedHashmap.get()</code> would give me.</p>
  <p>We use a cache to get fast lookups if an element is in the cache, if the lookup is slow, there is no point in caching it. I also tried <code>getAllPresent(a)</code> and <code>asMap()</code> but it gives equal performance.</p>
  <p>Library version is: <em>guava-11.0.1.jar</em></p>
  <p>LoadingCache is defined as follows:</p>
  <pre><code>LoadingCache&lt;TileKey, Bitmap&gt; tiles = CacheBuilder.newBuilder().maximumSize(100).build(new CacheLoader&lt;TileKey,Bitmap&gt;() {
              @Override
              public Bitmap load(TileKey tileKey) {
              System.out.println(&quot;Loading in &quot; + Thread.currentThread().getName() + &quot; &quot;
                  + tileKey.x + &quot;-&quot; + 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);
              }
          });
  </code></pre>
  <p><strong>My questions are:</strong></p>
  <ul>
  <li>Do I use it wrong?</li>
  <li>Is its implementation unsuitable for Android?</li>
  <li>Did i miss a configuration option?</li>
  <li>Is this a known issue with the Cache that's being worked on?</li>
  </ul>
  <p>Update:</p>
  <p>After about 100 frames painted the CacheStats are:</p>
  <pre><code>I/System.out( 6989): CacheStats{hitCount=11992, missCount=97,
  loadSuccessCount=77, loadExceptionCount=0, totalLoadTime=1402984624, evictionCount=0}
  </code></pre>
  <p>After that <code>missCount</code> stays basicly the same as <code>hitCount</code> increments. In this case the cache is big enough for loads to happen sparsely, but <code>getIfPresent()</code> is slow nontheless.</p>