2015-07-20 5 views
1

У меня возникла странная проблема, когда я использовал мягкую ссылку на Android. я реализовал класс для кэша растрового, исходный код выглядит следующим образом:Софт-ссылка не работает должным образом на Android

public class ImageCache 
{ 
    private static HashMap<String, SoftReference<Bitmap>> mCache = new HashMap<String, SoftReference<Bitmap>>(); 
    private static final String TAG = "ImageCache"; 
    public static Bitmap getBitmap(String url) 
    { 
     Bitmap bitmap = null; 
     if (mCache.containsKey(url)) 
     { 
      Log.d(TAG, "use cache: " + url); 
      bitmap = mCache.get(url).get(); 
      if (bitmap != null) 
      { 
       return bitmap; 
      } 
      else 
      { 
       Log.w(TAG, "#######################soft ref was collected!!!"); 
      } 
     } 
     bitmap = BitmapFactory.decodeFile(url); 

     if (bitmap == null) 
     { 
      Log.e(TAG, "#####jpg not found"); 
      return null; 
     } 
     bitmap = Bitmap.createScaledBitmap(bitmap, 320, 240, false); 
     synchronized (mCache) { 
      mCache.put(url, new SoftReference<Bitmap>(bitmap)); 
     } 
     return bitmap; 
    } 
} 

Но я нашел через LogCat, что мягкая ссылка собираются часто. Журнал:

#######################soft ref was collected!!! 

Насколько я знаю, мягкие ссылки будут собраны с помощью ОГО, только если Java кучи вырастет до своего предела, и нет места для нового распределения памяти.

Но почему мягкая ссылка на Android не ведет себя так, как ожидалось?

+0

контрольный счет для растрового изображения может быть 0 .. думаю. («мягкое» реферирование сохраняется в mCache, но я не могу найти другую ссылку на растровое изображение) – Toris

+0

Не рекомендуется использовать SoftReference для кеша. Вместо этого используйте LRUCache. – songchenwen

ответ

3

Насколько я знаю, мягкая ссылка будет собрана GC, только если куча java вырастет до предела, и нет места для нового распределения памяти.

Это неверное описание.

Согласно Oracle documentation, любое данное SoftReference может быть собрано в любое время, если GC примет решение об этом. Существует даже параметр VM, называемый -XX:SoftRefLRUPolicyMSPerMB. Таким образом, SoftReferences - , означало, чтобы очиститься, прежде чем увеличивать размер кучи даже на настольных JVM (см. Также this question для получения дополнительной информации по этому вопросу).

Android documentation дает еще меньше гарантий, и clearly warns, что виртуальная машина не будет на самом деле настаивают на сохранении этих ссылок вокруг долгое время:

В отличие от WeakReference, SoftReference не будет очищен и не помещён до тех пор, runtime должен вернуть память для удовлетворения распределения.

Который я лично читаю как «до следующего GC_FOR_ALLOC».

Конечно, для SoftReferences существует определенное применение, например, их circuit breaker. Связанная статья также объясняет, почему кеширование не является одним из них. Если вы хотите управлять своим кешем в манере, это действительно имеет значение, используйте ограниченную памятью LruCache и очистите это от onLowMemory(). Или, еще лучше, просто отпустите Bitmaps после их использования и позвольте ОС решить, что нужно кэшировать и когда уничтожать ваше приложение, и это кеши.

+1

Если мягкая ссылка почти одинакова со слабым эталоном, какова цель определения двух ссылок почти одинаково? – dragonfly

+1

@dragonfly Я уточнил эту часть ответа. В принципе, мягкие ссылки не получаются, по крайней мере, до следующего * stop-the-world * (также известного как * «собирать мусор, чтобы избежать увеличения размера кучи» *) GC, в то время как слабые могут быть удалены во время любого другого GC (такой как обычный параллельный GC). По крайней мере, так звучит для меня часть документации. – user1643723