LruBitmapPool
LruBitmapPool為何而生呢?
摘抄自網(wǎng)上的一段解釋:
alvik和ART都沒(méi)有使用compacting garbage collector垃圾回收模式,這種模式中GC會(huì)遍歷堆,同時(shí)把活躍對(duì)象移到相鄰內(nèi)存區(qū)域,讓更大的內(nèi)存塊可以用在后續(xù)的分配中。因?yàn)榘沧繘](méi)有這種模式,就可能會(huì)出現(xiàn)被分配的對(duì)象分散在各處,對(duì)象之間只有很小的內(nèi)存可用。如果應(yīng)用試圖分配一個(gè)大于鄰近的閑置內(nèi)存塊空間的對(duì)象,就會(huì)導(dǎo)致OOM崩潰,即使總的空余內(nèi)存空間大于要分配的對(duì)象的大小。
而且,同步GC時(shí)會(huì)暫停所有線程(包括UI主線程)以便進(jìn)行GC,雖然暫停時(shí)間很短,但頻繁的同步GC會(huì)造成頁(yè)面卡頓,從而影響用戶體驗(yàn)。
因此為了避免頻繁的創(chuàng)建以及回收Bitmap對(duì)象,進(jìn)而減少GC的出現(xiàn),可以使用BitmapPool統(tǒng)一的管理Bitmap的創(chuàng)建以及重用。
使用LruBitmapPool后解決了些什么問(wèn)題呢?
因?yàn)镚lide提供了LruBitmapPool方法,從而使用圖片的加載進(jìn)一步高效化,從上面的解釋,簡(jiǎn)單概括就是避免Bitmap的頻繁創(chuàng)建,提高復(fù)用,減少了內(nèi)存抖動(dòng)
內(nèi)存抖動(dòng)是由于短時(shí)間內(nèi)有大量對(duì)象進(jìn)出Young Generiation區(qū)導(dǎo)致的,它伴隨著頻繁的GC。
LruBitmapPool源碼剖析

從圖中大致可以了解到其LruBitmapPool調(diào)用流程(注意如果使用into(target)方法則不會(huì)使用LruBitmapPool機(jī)制),在位圖轉(zhuǎn)換的時(shí)候去查找LruBitmapPool中是否存在大小和配置信息相同的bitmap,有則返回
主要方法
put方法
@Override
public synchronized void put(Bitmap bitmap) {
if (bitmap == null) {
throw new NullPointerException("Bitmap must not be null");
}
if (bitmap.isRecycled()) {
throw new IllegalStateException("Cannot pool recycled bitmap");
}
if (!bitmap.isMutable() || strategy.getSize(bitmap) > maxSize
|| !allowedConfigs.contains(bitmap.getConfig())) {
bitmap.recycle();
return;
}
final int size = strategy.getSize(bitmap);
strategy.put(bitmap);//存入LruPoolStrategy中
tracker.add(bitmap);
puts++;
currentSize += size;
dump();//輸出log信息
evict();//根據(jù)currentSize計(jì)算是否超出maxSize,是則進(jìn)行末位回收
}
get方法
傳入大小及配置信息來(lái)查找相匹配的位圖
@Override
@NonNull
public Bitmap get(int width, int height, Bitmap.Config config) {
Bitmap result = getDirtyOrNull(width, height, config);
if (result != null) {
result.eraseColor(Color.TRANSPARENT);//如果對(duì)象池存在位圖則擦拭該位圖像素
} else {
result = Bitmap.createBitmap(width, height, config);//創(chuàng)新新的位圖
}
return result;
}
getDirtyOrNull方法
@Nullable
private synchronized Bitmap getDirtyOrNull(int width, int height, Bitmap.Config config) {
assertNotHardwareConfig(config);
final Bitmap result = strategy.get(width, height, config != null ? config : DEFAULT_CONFIG);
if (result == null) {
misses++;
} else {
hits++;
currentSize -= strategy.getSize(result);
tracker.remove(result);
normalize(result);
}
dump();
return result;
}
在調(diào)用LruBitmapPool.get方法獲取到Bitmap后,通過(guò)如下方法將獲取到的bitmap作為參數(shù)傳給Canvas,在canvas中把inBitmap像素填充到進(jìn)去,通過(guò)對(duì)象復(fù)用,很好的優(yōu)化了內(nèi)存抖動(dòng)問(wèn)題
private static void applyMatrix(@NonNull Bitmap inBitmap, @NonNull Bitmap targetBitmap,
Matrix matrix) {
BITMAP_DRAWABLE_LOCK.lock();
try {
Canvas canvas = new Canvas(targetBitmap);
canvas.drawBitmap(inBitmap, matrix, DEFAULT_PAINT);
clear(canvas);
} finally {
BITMAP_DRAWABLE_LOCK.unlock();
}
}