【Glide】缓存大小的计算策略

MemorySizeCalculator

源码

MemorySizeCalculator(MemorySizeCalculator.Builder builder) {
    this.context = builder.context;

    arrayPoolSize =
        isLowMemoryDevice(builder.activityManager)
            ? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR
            : builder.arrayPoolSizeBytes;
    int maxSize =
        getMaxSize(
            builder.activityManager, builder.maxSizeMultiplier, builder.lowMemoryMaxSizeMultiplier);

    int widthPixels = builder.screenDimensions.getWidthPixels();
    int heightPixels = builder.screenDimensions.getHeightPixels();
    int screenSize = widthPixels * heightPixels * BYTES_PER_ARGB_8888_PIXEL;

    int targetBitmapPoolSize = Math.round(screenSize * builder.bitmapPoolScreens);

    int targetMemoryCacheSize = Math.round(screenSize * builder.memoryCacheScreens);
    int availableSize = maxSize - arrayPoolSize;

    if (targetMemoryCacheSize + targetBitmapPoolSize <= availableSize) {
      memoryCacheSize = targetMemoryCacheSize;
      bitmapPoolSize = targetBitmapPoolSize;
    } else {
      float part = availableSize / (builder.bitmapPoolScreens + builder.memoryCacheScreens);
      memoryCacheSize = Math.round(part * builder.memoryCacheScreens);
      bitmapPoolSize = Math.round(part * builder.bitmapPoolScreens);
    }
  }

arrayPoolSize

// 默认缓存大小4MB.
static final int ARRAY_POOL_SIZE_BYTES = 4 * 1024 * 1024;
int arrayPoolSizeBytes = ARRAY_POOL_SIZE_BYTES;
private static final int LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR = 2;

arrayPoolSize =
    isLowMemoryDevice(builder.activityManager)
        ? builder.arrayPoolSizeBytes / LOW_MEMORY_BYTE_ARRAY_POOL_DIVISOR
        : builder.arrayPoolSizeBytes;

arrayPoolSize的默认大小是4M,如果是低内存手机,则取默认值的一半,即2M

memoryCacheSize和bitmapPoolSize

计算Glide最大可用内存maxSize,获取系统为每个app分配的内存,根据手机性能取一个系数,maxSize = 内存 * 系数

int maxSize =
     getMaxSize(
         builder.activityManager, builder.maxSizeMultiplier, builder.lowMemoryMaxSizeMultiplier);

static final float MAX_SIZE_MULTIPLIER = 0.4f;
static final float LOW_MEMORY_MAX_SIZE_MULTIPLIER = 0.33f;
@Synthetic float maxSizeMultiplier = MAX_SIZE_MULTIPLIER;
@Synthetic float lowMemoryMaxSizeMultiplier = LOW_MEMORY_MAX_SIZE_MULTIPLIER;

private static int getMaxSize(ActivityManager activityManager, float maxSizeMultiplier,
    float lowMemoryMaxSizeMultiplier) {
    
    获取系统分配给应用的默认内存
  final int memoryClassBytes = activityManager.getMemoryClass() * 1024 * 1024;
  final boolean isLowMemoryDevice = isLowMemoryDevice(activityManager);
  
  内存值乘以一个系数,如果是低内存手机,系数为0.33,其他为0.4
  return Math.round(memoryClassBytes * (isLowMemoryDevice ? lowMemoryMaxSizeMultiplier
      : maxSizeMultiplier));
}

屏幕大小 = 屏幕宽度 * 屏幕高度 * ARGB_8888模式下的Bitmap每个像素位数(4)

static final int BYTES_PER_ARGB_8888_PIXEL = 4;
屏幕宽度
int widthPixels = builder.screenDimensions.getWidthPixels();
屏幕高度
int heightPixels = builder.screenDimensions.getHeightPixels();
屏幕大小 
int screenSize = widthPixels * heightPixels * BYTES_PER_ARGB_8888_PIXEL;

预计算BitmapPoolSize和MemoryCacheSize,分别用上面的屏幕大小乘一个系数。

预计算BitmapPoolSize,builder.bitmapPoolScreens的值根据系统取4或者1
static final int BITMAP_POOL_TARGET_SCREENS =
    Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 4 : 1;
    
int targetBitmapPoolSize = Math.round(screenSize * builder.bitmapPoolScreens);

预计算MemoryCacheSize ,builder.memoryCacheScreens的值为2
int targetMemoryCacheSize = Math.round(screenSize * builder.memoryCacheScreens);

可用内存 = Glide最大使用内存 - arrayPoolSize
int availableSize = maxSize - arrayPoolSize;

如果两者之和小于可用内存,直接取值。否则按照两者的比例分配
if (targetMemoryCacheSize + targetBitmapPoolSize <= availableSize) {
  memoryCacheSize = targetMemoryCacheSize;
  bitmapPoolSize = targetBitmapPoolSize;
} else {
  float part = availableSize / (builder.bitmapPoolScreens + builder.memoryCacheScreens);
  memoryCacheSize = Math.round(part * builder.memoryCacheScreens);
  bitmapPoolSize = Math.round(part * builder.bitmapPoolScreens);
}

总结

首先,获取系统为app分配的内存,划分内存的一部分为Glide内存,低内存手机使用全部的0.33,正常使用0.4。

接下来,对Glide内存继续划分。arrayPool占用固定值,低内存占用2M,正常占用4M。

然后计算占满一个屏幕需要的内存screenSize,MemoryCacheSize =
screenSize * 2。BitmapPoolSize = screenSize * 4,如果sdk版本小于26 ,则BitmapPoolSize = screenSize * 1。

如果BitmapPoolSize + MemoryCacheSize小于Glide剩余的可用内存,则按照这个划分,如果剩余内存不够,则按照两者的比值进行划分。

要点

从中我们可以学习到,优秀的开源框架,在兼容方面做的非常好。

  • 内存的分配兼容了低内存系统
  • 兼容了SDK老版本的Bitmap

自己在做项目的内存管理时,要注意兼容低内存系统。同时,关注andorid sdk各版本特性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值