在当今高并发、大数据的年代,体系功能优化是非常重要的。而缓存优化作为进步体系功能的一种有效手法,被广泛运用于各种场景中。其间,冷热端别离和重排序是常见的两种缓存优化方法。本篇博客将具体介绍这两种优化方法的原理、完成和运用场景,期望能为您的体系功能优化提供帮助。

缓存优化是进步体系功能的一种有效手法,其间冷热端别离和重排序是常见的两种优化方法。

缓存优化

  1. 冷热端别离

缓存的命中率受多种要素影响,其间最重要的要素之一是缓存的巨细。在实践运用中,经常会遇到数据集非常大的情况,假如将悉数数据都放入缓存,那么缓存的命中率就会很低,然后影响体系的功能。此刻能够考虑选用冷热端别离的战略。

所谓冷热端别离,便是将数据集分为两个部分:冷数据和热数据。冷数据指的是拜访频率低的数据,能够不用放入缓存中,而热数据指的是拜访频率高的数据,应该优先放入缓存中。经过冷热端别离,能够有效地进步缓存的命中率,然后进步体系的功能。

  1. 重排序

在实践运用中,数据拜访的次序往往并不是随机的,而是有必定的规律。假如按照这种规律来拜访数据,能够有效地进步缓存的命中率。因而,能够选用重排序的战略来优化缓存。

所谓重排序,便是将数据按照必定的规矩从头排序,使得拜访频率高的数据排在前面,拜访频率低的数据排在后面。这样,在拜访数据时就能够先拜访排在前面的数据,然后进步缓存的命中率。

需求注意的是,重排序的战略需求依据具体的数据集来确认,不同的数据集可能需求不同的重排序战略。一起,重排序可能会添加必定的核算量,需求在功能和命中率之间做出平衡。

举个比如

Android 中运用冷热端别离和重排序战略进步图片加载缓存命中率的比如

class ImageLoader(private val context: Context) {
    private val memoryCache: LruCache<String, Bitmap>
    private val diskCache: DiskLruCache
    init {
        // 核算可用的最大内存
        val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
        // 取可用内存的 1/8 作为缓存巨细
        val cacheSize = maxMemory / 8
        memoryCache = object : LruCache<String, Bitmap>(cacheSize) {
            override fun sizeOf(key: String, value: Bitmap): Int {
                // 核算 Bitmap 的巨细,单位是 KB
                return value.byteCount / 1024
            }
        }
        // 获取磁盘缓存途径
        val cacheDir = context.externalCacheDir?.path ?: context.cacheDir.path
        val diskCacheDir = File(cacheDir + File.separator + "image_cache")
        if (!diskCacheDir.exists()) {
            diskCacheDir.mkdirs()
        }
        diskCache = DiskLruCache.open(diskCacheDir, 1, 1, 10 * 1024 * 1024)
    }
    //
    fun displayImage(url: String, imageView: ImageView) {
        val bitmap = memoryCache.get(url)
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap)
            return
        }
        loadFromDiskCache(url, imageView)
        loadFromNetwork(url, imageView)
    }
    private fun loadFromDiskCache(url: String, imageView: ImageView) {
        var bitmap: Bitmap? = null
        try {
            val snapshot = diskCache.get(url)
            if (snapshot != null) {
                val inputStream = snapshot.getInputStream(0)
                val fileDescriptor = (inputStream as FileInputStream).fd
                bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor)
                if (bitmap != null) {
                    memoryCache.put(url, bitmap)
                    imageView.setImageBitmap(bitmap)
                }
            }
        } catch (e: IOException) {
            e.printStackTrace()
        }
    }
    private fun loadFromNetwork(url: String, imageView: ImageView) {
        // 发送网络恳求获取图片数据
        // ...
        // 解码图片数据并显现
        val bitmap = decodeBitmapFromData(imageData, reqWidth, reqHeight)
        if (bitmap != null) {
            memoryCache.put(url, bitmap)
            try {
                val editor = diskCache.edit(url)
                if (editor != null) {
                    val outputStream = editor.newOutputStream(0)
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
                    editor.commit()
                }
            } catch (e: IOException) {
                e.printStackTrace()
            }
            imageView.setImageBitmap(bitmap)
        }
    }
    private fun decodeBitmapFromData(data: ByteArray, reqWidth: Int, reqHeight: Int): Bitmap? {
        // 解码图片数据并返回 Bitmap 目标
        // ...
    }
}

ImageLoader 类封装了图片加载的逻辑。它经过 LruCache 和 DiskLruCache 完成了冷热端别离的战略,将拜访频率高的图片放入 LruCache 中,而将不常用的图片放入 DiskLruCache 中。在加载图片时,先从 LruCache 中查找图片是否现已缓存,假如现已缓存则直接显现,否则从 DiskLruCache 中查找,假如也没有找到图片,则经过网络恳求获取图片并缓存到 LruCache 和 DiskLruCache 中,最终显现在 ImageView 中。

在这个比如中,重排序的完成主要体现在加载图片的次序上,先从 LruCache 中查找缓存,然后再从 DiskLruCache 中查找缓存,最终才进行网络恳求获取图片数据。这样的次序能够最大限度地进步缓存命中率,削减网络恳求的次数,一起也能够缩短图片加载的时间。

冷热端别离的完成则体现在将不常用的图片放入 DiskLruCache 中。由于 DiskLruCache 的读写速度相对较慢,所以将不常用的图片放入其间能够防止 LruCache 的缓存被占满,导致缓存筛选频频的问题。这样能够保证常用的图片能够始终缓存在 LruCache 中,进步缓存命中率。

其他运用场景和已用场景

  1. RecyclerView 中的 ViewHolder 缓存:在 RecyclerView 中,ViewHolder 是用来复用 item 视图的。经过将频频拜访的 View 缓存起来,能够大大进步 RecyclerView 的滑动功能,特别是在数据集较大的情况下。(多布局或许谈论列表类型的)
  2. 数据库查询:在数据库查询时,能够依据数据的运用频率将热数据和冷数据别离,并对热数据进行缓存,然后进步查询功能。
  3. JIT(Just-In-Time)编译器:在 Android 中,JIT 编译器将字节码编译成本地代码,以进步运用的履行速度。重排序能够优化 JIT 编译器的代码生成进程,进步编译速度和履行速度。
  4. UI 界面烘托:在 UI 界面烘托时,能够运用冷热别离的方法将常用的布局和组件缓存起来,防止每次从头烘托,然后进步界面的响应速度和功能。
  5. 动态加载类:在运用中运用反射动态加载类时,能够经过重排序优化类加载的进程,进步运用的响应速度。
  6. 预加载资源:在运用启动时,能够运用冷热别离的方法预加载一些常用的资源,防止比及需求运用时再加载,然后进步运用的启动速度和功能。
  7. 网络恳求:在网络恳求时,能够运用冷热别离的方法将常用的数据缓存起来,防止重复恳求,然后进步运用的响应速度和功能。

其实玩儿的仍是那个思维

总结

玩儿东西仍是要弄明白这个东西的建立根底是什么,或许负面要素有哪些。比如:

  1. 需求有满足的数据支持冷热别离和重排序,否则这些优化可能不会带来显着的功能进步,甚至可能会造成额外的开销。
  2. 冷热别离和重排序的完成需求考虑数据的生命周期,防止数据被过错地缓存或毁掉。
  3. 冷热别离和重排序可能会导致数据的展现次序不符合用户的期望,需求进行恰当的处理,以保证数据的展现作用。
  4. 在完成时需求考虑多线程安全问题,防止因并发拜访导致的数据错乱或其他异常情况。
  5. 在运用冷热别离和重排序时需求进行充分的测试和功能分析,以保证这些优化技能能够达到预期的功能进步作用,并且不会引进新的问题和危险。