2012-02-14 46 views
18

Chúng tôi sử dụng tải Tải xuống Google Gava cho bitmap trong ứng dụng Android. Trong ứng dụng, tôi đang chạy một Thread vẽ, vẽ các bitmap trong bộ nhớ cache đến một Canvas. Nếu một bitmap cụ thể không có trong bộ nhớ cache, nó sẽ không được rút ra để không tải sẽ bao giờ chặn Chủ đề vẽ.Hiệu suất kém với Bộ nhớ cache ổi trên Android

Tuy nhiên, kết quả vẽ trong nói lắp hình ảnh và tốc độ khung hình trên giây không phải là cách chúng tôi muốn. Tôi đóng đinh nó xuống phương thức của bộ nhớ cache getIfPresent(). Điều đó một mình chiếm hơn 20% tổng số ứng dụng của CPU. Trong getIfPresent()LocalCache$Segment.get() mất hơn 80% thời gian:

profiling-guava-cache.jpg

Ghi nhớ, đây chỉ là một tra cứu của một bitmap đã hiện diện. Sẽ không bao giờ xảy ra tải trong get(). Tôi đã tìm thấy sẽ có một chi phí sổ sách kế toán trong get() cho hàng đợi LRU quyết định việc trục xuất nào xảy ra nếu phân đoạn đầy. Nhưng điều này ít nhất là một đơn đặt hàng có cường độ chậm hơn so với mức Key-Lookup trong số LRU-LinkedHashmap.get() sẽ cho tôi.

Chúng tôi sử dụng bộ nhớ cache để tra cứu nhanh nếu phần tử nằm trong bộ nhớ cache, nếu tra cứu chậm, không có điểm nào trong bộ đệm ẩn. Tôi cũng đã thử getAllPresent(a)asMap() nhưng nó mang lại hiệu suất như nhau.

Library phiên bản là: ổi-11.0.1.jar

LoadingCache được định nghĩa như sau:

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); 
      } 
     }); 

Câu hỏi của tôi là:

  • Tôi sử dụng nó sai rồi?
  • Việc triển khai có thực sự không khả thi đối với Android không?
  • Tôi có bỏ lỡ tùy chọn cấu hình không?
  • Đây có phải là sự cố đã biết với Cache đang được thực hiện không?

Cập nhật:

Sau khoảng 100 khung sơn các CacheStats là:

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

Sau missCount mà vẫn về cơ bản giống như gia hitCount. Trong trường hợp này, bộ nhớ cache đủ lớn để tải xuống xảy ra thưa thớt, nhưng getIfPresent chậm không nontheless.

+1

Vui lòng không in đậm mọi cụm từ khác; rất khó đọc nên tôi đã gửi một bản chỉnh sửa để lấy nó ra. – simchona

+0

Cảm ơn bạn, simchona đã chỉnh sửa nó để làm cho nó dễ đọc hơn. – user643011

+0

Bạn có thể đăng các kết quả của 'tiles.cacheStats()'? –

Trả lời

30

CacheBuilder được thiết kế cho bộ nhớ đệm phía máy chủ, trong đó đồng thời là mối quan tâm chính. Do đó nó giao dịch trên chi phí đơn luồng và bộ nhớ để đổi lấy hành vi đa luồng tốt hơn. Nhà phát triển Android nên sử dụng LruCache, LinkedHashMap hoặc tương tự ở nơi hiệu suất và bộ nhớ luồng đơn là những mối quan tâm chính. Trong tương lai có thể có concurrencyLevel = 0 để chỉ ra rằng bộ nhớ cache nhẹ, không đồng thời là bắt buộc.

+1

Tôi đã thử concurrencyLevel = 1, nhưng nó không cải thiện thời gian truy cập. concurrencyLevel = 0 dẫn đến lỗi. Thật vậy, AtomicReferenceArray mất một lượng thời gian CPU đáng kể. Tôi sẽ đi cho android.util.LruCache bây giờ. Cảm ơn bạn đã bình luận về kiến ​​trúc ARM và câu trả lời dài dòng của bạn. Tôi rất thích xem concurrencyLevel = 0 trong tương lai. – user643011

+1

concurrencyLevel = 1 nghĩa là người viết đơn, nhiều người đọc. Điều đó không cung cấp nhiều đơn giản hóa để làm việc. Một mức 0 sẽ cho biết người đọc được đồng bộ với ghi, vì vậy một phiên bản đồng bộ có thể được thực hiện. Khi tôi mã xem xét LruCache chúng tôi vẫn đang làm việc trên giao diện Cache, do đó, nó là ưu tiên thấp để thêm concurrencyLevel = 0 vào MapMaker. Vì vậy LruCache được sinh ra. –

+4

FYI, LruCache cũng có sẵn trước Honeycomb trong thư viện tương thích. http://developer.android.com/sdk/compatibility-library.html –

2

Mã Android không phải lúc nào cũng được tối ưu hóa giống như cách trong JVM. Những gì có thể thực hiện rất tốt trong Java có thể không hoạt động tốt trong Android. Tôi đề nghị bạn viết một bộ nhớ cache rất đơn giản của riêng bạn. ví dụ. sử dụng LinkedHashMap.removeEldestEntry() và xem cách thực hiện.

Các vấn đề liên quan