Android学习总结之Glide自定义三级缓存(实战篇)

一、为什么需要三级缓存

内存缓存(Memory Cache)

内存缓存旨在快速显示刚浏览过的图片,例如在滑动列表时来回切换的图片。在 Glide 中,内存缓存使用 LruCache 算法(最近最少使用),能自动清理长时间未使用的图片,以此确保内存的合理利用。通常,内存缓存限制在手机可用内存的 15%。举例来说,若手机拥有 8GB 内存,内存缓存大约为 1.2GB。同时,为了进一步优化,图片会按屏幕尺寸进行压缩,比如原图为 2000px,而手机屏幕为 1000px,那么只存储 1000px 版本的图片。当内存缓存超出限制时,会自动清理超出部分的图片。

代码实现

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.module.AppGlideModule;public class CustomGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {// 获取设备的最大内存int maxMemory = (int) Runtime.getRuntime().maxMemory();// 计算内存缓存的大小,这里设置为最大内存的15%int memoryCacheSize = maxMemory / 1024 / 1024 * 15;// 创建LruResourceCache对象builder.setMemoryCache(new LruResourceCache(memoryCacheSize));}
}

磁盘缓存(Disk Cache)

磁盘缓存用于存储常用但当前不在内存中的图片,像用户经常访问的商品详情页图片。Glide 通过 DiskLruCache 将图片存储在手机硬盘上,总容量一般设置为 100MB,并且优先存储高质量图片。为了优化存储,图片按 URL 哈希值命名文件,这样可以避免重复存储相同图片。同时,对于超过 7 天未使用的图片,会自动进行清理。

代码实现

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;
import com.bumptech.glide.module.AppGlideModule;public class CustomDiskCacheGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {// 设置磁盘缓存的路径String diskCachePath = context.getCacheDir().getPath() + "/glide_cache";// 设置磁盘缓存的大小为100MBint diskCacheSize = 1024 * 1024 * 100;// 创建DiskLruCacheFactory对象builder.setDiskCache(new DiskLruCacheFactory(diskCachePath, diskCacheSize));}
}

网络缓存(Network Cache)

网络缓存的作用是避免重复从服务器下载相同图片,这需要结合 HTTP 缓存头来实现。Glide 借助 OkHttp 的缓存机制,将图片存储在路由器或基站缓存中,总容量设置为 50MB,优先存储高频访问的图片。通过根据 HTTP 的 Cache-Control 头设置缓存时间(例如设置为 1 天),以及在图片 URL 中添加版本号(如 image_v2.jpg),当版本更新时强制重新下载,从而实现高效的网络缓存管理。

代码实现

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import okhttp3.Cache;
import okhttp3.OkHttpClient;import java.io.InputStream;public class CustomNetworkCacheGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {// 设置网络缓存的路径Cache cache = new Cache(context.getCacheDir(), 1024 * 1024 * 50);// 创建OkHttpClient对象并设置缓存OkHttpClient client = new OkHttpClient.Builder().cache(cache).build();// 注册OkHttpUrlLoader,让Glide使用OkHttp进行网络请求registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));}
}

整合代码: 

import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.LruResourceCache;
import com.bumptech.glide.module.AppGlideModule;/*** 自定义Glide内存缓存配置* 通过LruCache算法实现最近最少使用的图片自动回收*/
public class CustomGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {// 获取应用可使用的最大内存(单位:字节)int maxMemory = (int) Runtime.getRuntime().maxMemory();// 计算内存缓存大小(15%的可用内存)int memoryCacheSize = maxMemory / 1024 / 1024 * 15;// 创建LruResourceCache并设置缓存大小builder.setMemoryCache(new LruResourceCache(memoryCacheSize));}
}import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.load.engine.cache.DiskLruCacheFactory;
import com.bumptech.glide.module.AppGlideModule;/*** 自定义Glide磁盘缓存配置* 使用DiskLruCache将图片持久化到本地存储*/
public class CustomDiskCacheGlideModule extends AppGlideModule {@Overridepublic void applyOptions(Context context, GlideBuilder builder) {// 设置磁盘缓存路径(应用缓存目录下的glide_cache文件夹)String diskCachePath = context.getCacheDir().getPath() + "/glide_cache";// 设置磁盘缓存大小(100MB)int diskCacheSize = 1024 * 1024 * 100;// 创建DiskLruCache工厂并设置路径和大小builder.setDiskCache(new DiskLruCacheFactory(diskCachePath, diskCacheSize));}
}import android.content.Context;
import com.bumptech.glide.Glide;
import com.bumptech.glide.GlideBuilder;
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
import com.bumptech.glide.load.model.GlideUrl;
import com.bumptech.glide.module.AppGlideModule;
import okhttp3.Cache;
import okhttp3.OkHttpClient;import java.io.InputStream;/*** 自定义Glide网络缓存配置* 结合OkHttp实现HTTP级别的网络缓存*/
public class CustomNetworkCacheGlideModule extends AppGlideModule {@Overridepublic void registerComponents(Context context, Glide glide, Registry registry) {// 创建OkHttp缓存(50MB,位于应用缓存目录)Cache cache = new Cache(context.getCacheDir(), 1024 * 1024 * 50);// 构建带缓存的OkHttpClientOkHttpClient client = new OkHttpClient.Builder().cache(cache).build();// 注册OkHttp为Glide的网络请求引擎registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));}
}

常见问题解决方案

  1. 缓存穿透:缓存穿透指查询一个一定不存在的数据,由于缓存不命中需要从数据库查询,查不到数据则不写入缓存,导致该不存在的数据每次请求都要到数据库查询,给数据库带来压力。在 Glide 中,可以通过设置错误占位图、加载占位图和空值占位图来解决部分问题。例如:
Glide.with(context).load(url).error(R.drawable.ic_error) // 设置错误占位图.placeholder(R.drawable.ic_loading) // 设置加载占位图.fallback(R.drawable.ic_fallback) // 设置空值占位图.into(imageView);

在大厂面试中,关于缓存穿透常被问到的问题有:“请简述缓存穿透的概念以及可能的解决方案”。回答时,除了像上述代码那样通过 Glide 的占位图设置来应对外,还可以提及如使用布隆过滤器(Bloom Filter)等方案。布隆过滤器是一种空间效率极高的概率型数据结构,它利用位数组和哈希函数来判断一个元素是否在一个集合中。将所有已存在的数据 key 放入布隆过滤器中,当新的请求到来时,先通过布隆过滤器判断该 key 是否存在。如果不存在,直接返回,避免查询数据库,从而有效减少不必要的数据库查询,提高系统性能。

  1. 缓存雪崩:缓存雪崩是指在某一时刻,大量缓存同时失效,导致大量请求直接访问数据库,造成数据库压力过大甚至崩溃。可以通过设置不同的缓存过期时间来避免,例如:
int cacheDuration = TimeUnit.HOURS.toMillis(24) + new Random().nextInt(3600000);

面试中可能会被问到:“如何防止缓存雪崩的发生”。除了上述设置随机过期时间的方法外,还可以采用二级缓存策略,即设置主缓存和备用缓存。主缓存失效后,先从备用缓存获取数据,同时对主缓存进行异步更新,这样可以在一定程度上缓解大量请求直接冲击数据库的问题。另外,使用互斥锁也是一种思路,在缓存失效时,只有一个线程能够获取锁去更新缓存,其他线程等待,避免大量线程同时查询数据库。

  1. OOM 预防:OOM(Out Of Memory,内存溢出)在图片加载中较为常见,因为图片占用内存较大。可以通过使用 RGB_565 格式减少内存占用,例如:
// 使用RGB_565格式减少内存占用
Glide.with(context).load(url).format(DecodeFormat.PREFER_RGB_565).into(imageView);

面试官可能会问:“在 Glide 中,如何预防 OOM 问题”。除了设置图片格式外,还可以根据设备内存情况动态调整图片尺寸。例如,获取设备的可用内存,当内存较低时,对图片进行更大比例的压缩。同时,合理配置 Glide 的内存缓存大小也很关键,避免缓存占用过多内存。此外,及时释放不再使用的图片资源,Glide 通过与 Activity 或 Fragment 的生命周期绑定,在界面不可见时及时清理相关图片资源,防止内存泄漏。

关键指标的获取途径

  1. 冷启动加载时间:借助 Android Profiler 的 Timeline 功能来精准测量。在应用启动时,启动 Profiler 并记录图片加载所耗费的时长。代码示例如下:
long startTime = System.currentTimeMillis();
Glide.with(this).load(url).into(imageView);
long duration = System.currentTimeMillis() - startTime;
Log.d("GlideTest", "加载耗时: " + duration + "ms");
  1. 内存峰值占用情况:使用 Android Profiler 的 Memory Monitor 进行监测。在滑动列表时,留意 Heap Size 的变化趋势,对比开启缓存前后 Bitmap 内存占用的差异,以此来优化内存使用。
  2. 缓存命中率计算:通过 Glide 的日志输出(设置 Glide.get (context).setLogLevel (Log.DEBUG)),从日志中筛选出 Fetched 和 Decoded 相关的条目。缓存命中率 = (内存命中数 + 磁盘命中数)÷ 总请求数 × 100%。
  3. FPS 帧率监控:采用 Android Profiler 的 FrameMetrics 功能。在滑动列表的过程中,记录丢帧的数量,确保平均帧率稳定在 55fps 以上,以保证流畅的用户体验。

二、自定义图片缓存框架

设计思路

  1. 内存缓存:运用 LruCache(Least Recently Used Cache,最近最少使用缓存)实现内存缓存,它能够自动回收最近最少使用的图片,保障内存的合理使用。
  2. 磁盘缓存:利用 DiskLruCache 实现磁盘缓存,将图片持久化到本地磁盘,方便在网络不可用或需要重复使用图片时快速获取。
  3. 多级缓存策略:首先从内存缓存中查找图片,若未找到则从磁盘缓存中查找,最后才从网络请求图片。当从网络获取到图片后,同时将其存入内存缓存和磁盘缓存。

代码实现

import android.graphics.Bitmap;
import android.util.LruCache;/*** 内存缓存实现* 使用LruCache(最近最少使用)算法管理内存中的图片*/
public class MemoryCache {// LruCache实例,用于存储图片(键为图片URL,值为Bitmap)private LruCache<String, Bitmap> lruCache;public MemoryCache() {// 获取应用最大可用内存(KB)int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);// 设置缓存大小为最大内存的1/8int cacheSize = maxMemory / 8;// 初始化LruCache并重写sizeOf方法计算每个Bitmap的大小lruCache = new LruCache<String, Bitmap>(cacheSize) {@Overrideprotected int sizeOf(String key, Bitmap bitmap) {// 返回Bitmap占用的内存大小(KB)return bitmap.getByteCount() / 1024;}};}// 向缓存添加图片public void put(String key, Bitmap bitmap) {if (get(key) == null) {lruCache.put(key, bitmap);}}// 从缓存获取图片public Bitmap get(String key) {return lruCache.get(key);}// 从缓存移除图片public void remove(String key) {lruCache.remove(key);}
}import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import com.jakewharton.disklrucache.DiskLruCache;import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;/*** 磁盘缓存实现* 使用DiskLruCache将图片持久化到本地存储*/
public class DiskCache {// 应用版本(用于缓存版本控制)private static final int APP_VERSION = 1;// 每个缓存项对应的值数量private static final int VALUE_COUNT = 1;// 磁盘缓存最大容量(10MB)private static final long CACHE_SIZE = 10 * 1024 * 1024;// DiskLruCache实例private DiskLruCache diskLruCache;public DiskCache(Context context) {try {// 获取缓存目录File cacheDir = getDiskCacheDir(context, "bitmap");if (!cacheDir.exists()) {cacheDir.mkdirs();}// 打开DiskLruCache实例diskLruCache = DiskLruCache.open(cacheDir, APP_VERSION, VALUE_COUNT, CACHE_SIZE);} catch (IOException e) {e.printStackTrace();}}// 向磁盘缓存添加图片public void put(String key, Bitmap bitmap) {DiskLruCache.Editor editor = null;try {// 获取缓存编辑器editor = diskLruCache.edit(hashKeyForDisk(key));if (editor != null) {// 获取输出流并写入图片(JPEG格式,质量100%)OutputStream outputStream = editor.newOutputStream(0);if (bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)) {editor.commit();} else {editor.abort();}outputStream.close();}} catch (IOException e) {e.printStackTrace();}}// 从磁盘缓存获取图片public Bitmap get(String key) {try {// 获取缓存快照DiskLruCache.Snapshot snapshot = diskLruCache.get(hashKeyForDisk(key));if (snapshot != null) {// 从输入流解码BitmapInputStream inputStream = snapshot.getInputStream(0);return BitmapFactory.decodeStream(inputStream);}} catch (IOException e) {e.printStackTrace();}return null;}// 从磁盘缓存移除图片public void remove(String key) {try {diskLruCache.remove(hashKeyForDisk(key));} catch (IOException e) {e.printStackTrace();}}// 获取磁盘缓存目录private File getDiskCacheDir(Context context, String uniqueName) {String cachePath;// 判断外部存储是否可用if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())||!Environment.isExternalStorageRemovable()) {cachePath = context.getExternalCacheDir().getPath();} else {cachePath = context.getCacheDir().getPath();}return new File(cachePath + File.separator + uniqueName);}// 生成URL的MD5哈希值作为缓存键private String hashKeyForDisk(String key) {String cacheKey;try {// 使用MD5算法生成哈希值final MessageDigest mDigest = MessageDigest.getInstance("MD5");mDigest.update(key.getBytes());cacheKey = bytesToHexString(mDigest.digest());} catch (NoSuchAlgorithmException e) {// 若不支持MD5,使用普通哈希码cacheKey = String.valueOf(key.hashCode());}return cacheKey;}// 字节数组转十六进制字符串private String bytesToHexString(byte[] bytes) {StringBuilder sb = new StringBuilder();for (byte b : bytes) {String hex = Integer.toHexString(0xFF & b);if (hex.length() == 1) {sb.append('0');}sb.append(hex);}return sb.toString();}
}import android.content.Context;
import android.graphics.Bitmap;/*** 多级缓存管理器* 统一管理内存缓存和磁盘缓存*/
public class ImageCacheManager {// 内存缓存实例private MemoryCache memoryCache;// 磁盘缓存实例private DiskCache diskCache;public ImageCacheManager(Context context) {memoryCache = new MemoryCache();diskCache = new DiskCache(context);}// 同时存入内存缓存和磁盘缓存public void put(String key, Bitmap bitmap) {memoryCache.put(key, bitmap);diskCache.put(key, bitmap);}// 优先从内存缓存获取,再从磁盘缓存获取public Bitmap get(String key) {Bitmap bitmap = memoryCache.get(key);if (bitmap != null) {return bitmap;}bitmap = diskCache.get(key);if (bitmap != null) {// 从磁盘读取后存入内存,提升下次访问速度memoryCache.put(key, bitmap);}return bitmap;}
}
  1. 请简述三级缓存(内存缓存、磁盘缓存、网络缓存)的作用和原理。

    • 内存缓存:旨在快速显示刚浏览过的图片,使用 LruCache 算法(最近最少使用),自动清理长时间未使用的图片,确保内存的合理利用。通常限制在手机可用内存的 15%。
    • 磁盘缓存:用于存储常用但当前不在内存中的图片,通过 DiskLruCache 将图片存储在手机硬盘上,设置总容量(如 100MB),优先存储高质量图片,按 URL 哈希值命名文件以避免重复存储,超过 7 天未使用的图片会自动清理。
    • 网络缓存:避免重复从服务器下载相同图片,结合 HTTP 缓存头,借助 OkHttp 的缓存机制,将图片存储在路由器或基站缓存中,设置总容量(如 50MB),优先存储高频访问的图片,根据 HTTP 的 Cache-Control 头设置缓存时间,并在图片 URL 中添加版本号以强制重新下载。
  2. 在自定义图片缓存框架中,LruCache 和 DiskLruCache 分别是如何实现的?

    • LruCache:在内存缓存类中,获取应用程序运行时的最大可用内存,使用最大可用内存的一部分(如 1/8)作为 LruCache 的缓存大小。重写 sizeOf 方法,计算每个图片对象占用的内存大小,通过 put 方法添加图片到缓存,get 方法获取图片,remove 方法移除图片。
    • DiskLruCache:在磁盘缓存类中,初始化时获取磁盘缓存的目录,打开 DiskLruCache 实例。put 方法通过获取编辑器和输出流,将图片以 JPEG 格式压缩并写入;get 方法通过获取快照和输入流,将输入流解码为 Bitmap 对象;remove 方法移除指定的图片。对键进行 MD5 哈希处理,确保键的唯一性。
  3. 如何防止缓存穿透、缓存雪崩和 OOM 问题?

    • 缓存穿透:在 Glide 中,可以通过设置错误占位图、加载占位图和空值占位图来解决部分问题。另外,可以使用布隆过滤器,将所有已存在的数据 key 放入布隆过滤器中,当新的请求到来时,先通过布隆过滤器判断该 key 是否存在,避免不必要的数据库查询。
    • 缓存雪崩:可以通过设置不同的缓存过期时间来避免,例如在设置缓存过期时间时,添加一个随机值。另外,采用二级缓存策略,设置主缓存和备用缓存,主缓存失效后,先从备用缓存获取数据,同时对主缓存进行异步更新。使用互斥锁,在缓存失效时,只有一个线程能够获取锁去更新缓存,其他线程等待。
    • OOM:在 Glide 中,可以使用 RGB_565 格式减少内存占用,根据设备内存情况动态调整图片尺寸,合理配置 Glide 的内存缓存大小,避免缓存占用过多内存。及时释放不再使用的图片资源,Glide 通过与 Activity 或 Fragment 的生命周期绑定,在界面不可见时及时清理相关图片资源,防止内存泄漏。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/79996.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux的文件查找与压缩

查找文件 find命令 # 命令&#xff1a;find 路径范围 选项1 选项1的值 \[选项2 选项2 的值…]# 作用&#xff1a;用于查找文档&#xff08;其选项有55 个之多&#xff09;# 选项&#xff1a;# -name&#xff1a;按照文档名称进行搜索&#xff08;支持模糊搜索&#xff0c;\* &…

python处理异常,JSON

异常处理 #异常处理 # 在连接MySQL数据库的过程中&#xff0c;如果不能有效地处理异常&#xff0c;则异常信息过于复杂&#xff0c;对用户不友好&#xff0c;暴露过多的敏感信息 # 所以&#xff0c;在真实的生产环境中&#xff0c; 程序必须有效地处理和控制异常&#xff0c;按…

线程的两种实现方式

线程的两种实现方式——内核支持线程&#xff08;kernal Supported Thread, KST&#xff09;&#xff0c; 用户级线程&#xff08;User Level Thread, ULT&#xff09; 1. 内核支持线程 顾名思义&#xff0c;内核支持线程即为在内核支持下的那些线程&#xff0c;它们的创建&am…

vue3基础学习(上) [简单标签] (vscode)

目录 1. Vue简介 2. 创建Vue应用 2.1 下载JS文件 2.2 引用JS文件 2.3 调用Vue方法​编辑 2.4 运行一下试试: 2.5 代码如下 3.模块化开发模式 3.1 Live Server插件 3.2 运行 4. 常用的标签 4.1 reactive 4.1.1 运行结果 4.1.2 代码: 4.2 ref 4.2.1 运行结果 4.2.2…

自定义分区器-基础

什么是分区 在 Spark 里&#xff0c;弹性分布式数据集&#xff08;RDD&#xff09;是核心的数据抽象&#xff0c;它是不可变的、可分区的、里面的元素并行计算的集合。 在 Spark 中&#xff0c;分区是指将数据集按照一定的规则划分成多个较小的子集&#xff0c;每个子集可以独立…

深入解析HTTP协议演进:从1.0到3.0的全面对比

HTTP协议作为互联网的基础协议&#xff0c;经历了多个版本的迭代演进。本文将详细解析HTTP 1.0、HTTP 1.1、HTTP/2和HTTP/3的核心特性与区别&#xff0c;帮助开发者深入理解网络协议的发展脉络。 一、HTTP 1.0&#xff1a;互联网的奠基者 核心特点&#xff1a; 短连接模式&am…

基于windows环境Oracle主备切换之后OGG同步进程恢复

基于windows环境Oracle主备切换之后OGG同步进程恢复 场景&#xff1a;db1是主库&#xff0c;db2是备库&#xff0c;ogg从db2备库抽取数据同步到目标数据库 db1 - db2(ADG) – ogg – targetdb 场景&#xff1a;db2是主库&#xff0c;db1是备库&#xff0c;ogg从db1备库抽取数…

微服务,服务粒度多少合适

项目服务化好处 复用性&#xff0c;消除代码拷贝专注性&#xff0c;防止复杂性扩散解耦合&#xff0c;消除公共库耦合高质量&#xff0c;SQL稳定性有保障易扩展&#xff0c;消除数据库解耦合高效率&#xff0c;调用方研发效率提升 微服务拆分实现策略 统一服务层一个子业务一…

【工奥阀门科技有限公司】签约智橙PLM

近日&#xff0c;工奥阀门科技有限公司正式签约了智橙泵阀行业版PLM。 忠于质量&#xff0c;臻于服务&#xff0c;精于研发 工奥阀门科技有限公司&#xff08;以下简称工奥阀门&#xff09;坐落于浙江永嘉&#xff0c;是一家集设计、开发、生产、销售、安装、服务为一体的阀门…

2025-5-15Vue3快速上手

1、setup和选项式API之间的关系 (1)vue2中的data,methods可以与vue3的setup共存 &#xff08;2&#xff09;vue2中的data可以用this读取setup中的数据&#xff0c;但是反过来不行&#xff0c;因为setup中的this是undefined &#xff08;3&#xff09;不建议vue2和vue3的语法混用…

基于智能推荐的就业平台的设计与实现(招聘系统)(SpringBoot Thymeleaf)+文档

&#x1f497;博主介绍&#x1f497;&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示&#xff1a;文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…

什么是路由器环回接口?

路由器环回接口&#xff08;LoopbackInterface&#xff09;是网络设备中的一种逻辑虚拟接口&#xff0c;不依赖物理硬件&#xff0c;但在网络配置和管理中具有重要作用。以下是其核心要点&#xff1a; 一、基本特性 1.虚拟性与稳定性 环回接口是纯软件实现的逻辑接口&#x…

HOT100 (滑动窗口子串普通数组矩阵)

先填坑 滑动窗口 3. 无重复字符的最长子串 给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。 思路:用一个uset容器存放当前滑动窗口中的元素 #include <bits/stdc++.h> using namespace std; class Solution {public:int lengthOfLongestSubstring(st…

工作实战之关于数据库表的备份

文章目录 1. dbeaver导出相关表到本地2. 使用sql语句3. 导入数据 1. dbeaver导出相关表到本地 常规情况下&#xff0c;如果想备份数据库的某张表&#xff0c;特别是临时备份或者表中数据不多的情况下&#xff0c;直接将数据库表中导出即可&#xff0c;后续可根据导出的insert语…

python克洛伊婚纱摄影预约管理系统

目录 技术栈介绍具体实现截图系统设计研究方法&#xff1a;设计步骤设计流程核心代码部分展示研究方法详细视频演示试验方案论文大纲源码获取/详细视频演示 技术栈介绍 Django-SpringBoot-php-Node.js-flask 本课题的研究方法和研究步骤基本合理&#xff0c;难度适中&#xf…

中间件-MQ常见问题

MQ常见问题 消息丢失消息会在哪些环节丢失应对机制 消息的顺序性消息幂等消息积压的处理 消息丢失 消息会在哪些环节丢失 网络传输环节&#xff1a;生产者发送消息到broker&#xff0c;broker中master同步消息给slave&#xff0c;consumer消费消息&#xff0c;这3个环节都是跨…

【python实用小脚本-63】每天花费2小时修复黑白照片,Python一键转换,节省90%时间(建议收藏)

一、应用场景故事 上周&#xff0c;我的朋友小李从家里翻出了一堆老照片&#xff0c;这些照片大多是彩色的&#xff0c;但他想把它们转换成黑白风格&#xff0c;让照片更有复古感。他尝试用Photoshop一张张处理&#xff0c;但花了整整一个周末&#xff0c;才处理了不到一半的照…

分页管理调试

一、分页管理原理 基本概念&#xff1a; 物理内存被划分为固定大小的页框&#xff08;Page Frame&#xff09;&#xff0c;逻辑地址空间被划分为相同大小的页&#xff08;Page&#xff09;。 通过页表&#xff08;Page Table&#xff09;实现逻辑地址到物理地址的映射。 逻辑…

搭建Hadoop集群standalone

在开始配置之前&#xff0c;请确保三台虚拟机都正确启动了&#xff01; 具体配置步骤如下。 1.上传spark安装包到某一台机器&#xff08;例如:hadoop100&#xff09;。 spark.3.1.2-bin-hadoop3.2.tgz。 2.解压。 把第一步上传的安装包解压到/opt/module下&#xff08;也可以…

AJAX技术全解析:从基础到最佳实践

目录 什么是 AJAX&#xff1f; 工作原理 XMLHttpRequest 基础 现代 Fetch API Axios 第三方库 数据处理 错误处理机制 跨域请求解决方案 最佳实践 总结 1. 什么是 AJAX&#xff1f; AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种通过浏览器与…