- 浏览: 11456 次
- 性别:
- 来自: 厦门
最新评论
转载请注明出处:[作者CJstar]http://blog.csdn.net/cj_star/article/details/48526867
为什么要使用内存缓存
内存缓存:
内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。
内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。
内存缓存的原理
JVM垃圾回收机制
JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
引用的类型
强引用:
只要引用存在,垃圾回收器就不会回收。
如:
A a = new A();
B b = new B();
a.b = b;
这时候b属于a的强引用,只有a被回收后b才能被回收。
软引用:
软引用是非必须的引用,当内存不足时可被回收的 。
如:
Java
A a = new A();
SoftRefernece<A> softA = new SoftRefernece<A>(a);
softA.get();//取A的值
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用:
第二次垃圾回收时回收
Java
A a = new A();
WeakReference<A> weakA = new WeakReference<A>(a);
weakA.get();//获取A对象
weakA.isEnQueued();//返回垃圾回收器是否将其标记为可回收。
软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!
虚引用:
每次JVM回收垃圾的时候都会被回收。
Java
A a = new A();
PhantomReference<A> phantomA = new PhantomReference<A>(a);
phantomA.get();//永远返回null
phantomA.isEnQueued();//返回内存中已删除
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
内存缓存的实现策略
Java
/**
* Created by CJstar on 15/9/2.
*/
public class LRUBitmapMemoryCache implements MemmoryCache<Bitmap> {
private static final String TAG = "LRUBitmapMemoryCache";
private MemoryCacheOptions options;
//强引用
private LruCache<String, Bitmap> mMemoryCache;
//软引用
private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
/**
* Create a instance by default config
*/
public LRUBitmapMemoryCache() {
options = new MemoryCacheOptions.Builder()
.setmMaxCacheCount(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHECOUNT)
.setmMaxCacheSize(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHESIZE)
.setmUseCache(DefaultConfig.MemoryCacheDefaultOptions.USECACHE)
.build();
initializeCache();
}
/**
* set a options as you set
*
* @param defaultOptions
*/
@Override
public void setOptions(MemoryCacheOptions defaultOptions) {
this.options = defaultOptions;
}
private void initializeCache() {
if (options == null) {
throw new VinciException("LRUBitmapMemoryCache#options is null");
}
if (options.getmMaxCacheSize() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache size is o");
}
if (options.getmMaxCacheCount() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache count is o");
}
MLog.d(TAG, "maxSize:" + options.getmMaxCacheSize() + " maxCount:" + options.getmMaxCacheCount());
mMemoryCache = new LruCache<String, Bitmap>(options.getmMaxCacheSize()) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
// TODO Auto-generated method stub
super.entryRemoved(evicted, key, oldValue, newValue);
if (oldValue != null) {
// the allocation is full, move bitmap to soft reference
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
testLog("entryRemoved to mSoftCache:" + key);
}
}
};
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
options.getmMaxCacheCount(), 0.75f, true) {
private static final long serialVersionUID = 6040103833179403725L;
@Override
protected boolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > options.getmMaxCacheCount()) {
testLog("removeEldestEntry true");
return true;
}
testLog("removeEldestEntry full");
return false;
}
};
}
@Override
public Bitmap get(String key) {
testLog("get:" + key);
if (TextUtils.isEmpty(key)) {
return null;
}
Bitmap bitmap;
// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);
if (bitmap != null && !bitmap.isRecycled()) {
// LRU : refresh this bitmap position
mMemoryCache.remove(key);
mMemoryCache.put(key, bitmap);
testLog("get mMemoryCache");
return bitmap;
}
}
// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null && !bitmap.isRecycled()) {
// move bitmap to mSoftCache
mMemoryCache.put(key, bitmap);
mSoftCache.remove(key);
testLog("get mSoftCache");
return bitmap;
} else {
// is recycled
mSoftCache.remove(key);
}
}
}
return null;
}
@Override
public boolean isExist(String key) {
if (TextUtils.isEmpty(key)) {
return false;
}
Bitmap bitmap;
// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}
// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}
}
return false;
}
@Override
public Bitmap remove(String key) {
// remove bitmap from mMemoryCache
Bitmap bitmap;
synchronized (mMemoryCache) {
bitmap = mMemoryCache.remove(key);
}
// remove bitmap from mSoftCache
synchronized (mSoftCache) {
if (bitmap != null && !bitmap.isRecycled()) {
mSoftCache.remove(key);
} else {
SoftReference<Bitmap> bitmapReference = mSoftCache.remove(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
}
}
}
return bitmap;
}
@Override
public void put(String key, Bitmap bitmap) {
if (bitmap == null || bitmap.isRecycled()) {
return;
}
testLog("put:" + key);
// thread synchronize
synchronized (mMemoryCache) {
mMemoryCache.put(key, bitmap);
}
}
@Override
public void clear() {
synchronized (mMemoryCache) {
mMemoryCache.evictAll();
}
synchronized (mSoftCache) {
mSoftCache.clear();
}
}
private final boolean ISDEBUG = false;
private void testLog(String str) {
if (ISDEBUG) {
MLog.e(TAG, str);
}
}
}
这个缓存是基于LRU算法的缓存机制,LRU即最久未使用算法,当内存不足时将最久未使用的对象放入软引用区,当内存不足时可以及时释放。
[项目的GitHub地址](https://github.com/CJstar/Vinci)
为什么要使用内存缓存
内存缓存:
内存缓存是指将已经赋值的对象保存在内存中,当再次使用的时候直接去内存读取,不再做重复的创建操作。
内存缓存的优势:
对象的重复使用,不再去创建对象,减少内存消耗,便于内存的集中管理。同时在需要读取数据库或者外存的时候,使用内存缓存将大大减少时间,提供程序的整体性能。
内存缓存的原理
JVM垃圾回收机制
JVM采用的是引用计数的机制,处理数据回收的问题。引用计数:即类被加载到内存以后,会在方法区,堆栈,以及程序计数器的地方分配相应的空间,同时对应产生一个引用计数器,专门计数对象被使用的情况。如果新的地方引用了对象,计数器就+1,引用销毁的时候计数器-1,当计数器为0的时候,对象被标记为可被回收。由于该机制不能处理互相引用的情况,加入了根搜索算法,解决互相引用时计数器始终>=1的情况。
引用的类型
强引用:
只要引用存在,垃圾回收器就不会回收。
如:
A a = new A();
B b = new B();
a.b = b;
这时候b属于a的强引用,只有a被回收后b才能被回收。
软引用:
软引用是非必须的引用,当内存不足时可被回收的 。
如:
Java
A a = new A();
SoftRefernece<A> softA = new SoftRefernece<A>(a);
softA.get();//取A的值
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
弱引用:
第二次垃圾回收时回收
Java
A a = new A();
WeakReference<A> weakA = new WeakReference<A>(a);
weakA.get();//获取A对象
weakA.isEnQueued();//返回垃圾回收器是否将其标记为可回收。
软引用第一次垃圾回收器扫描到的时候不会马上回收,会把它标记为可回收资源,第二次JVM回收内存的时候如果a还未被引用过,内存将被回收,这时softA.get()返回值是null。这样的好处是a对象可以短暂被保存,但是每次用get方法取值时都需要判断对象是否为空!
虚引用:
每次JVM回收垃圾的时候都会被回收。
Java
A a = new A();
PhantomReference<A> phantomA = new PhantomReference<A>(a);
phantomA.get();//永远返回null
phantomA.isEnQueued();//返回内存中已删除
虚引用是每次垃圾回收的时候都会被回收,通过虚引用的get方法永远获取到的数据为null,因此也被成为幽灵引用。
内存缓存的实现策略
Java
/**
* Created by CJstar on 15/9/2.
*/
public class LRUBitmapMemoryCache implements MemmoryCache<Bitmap> {
private static final String TAG = "LRUBitmapMemoryCache";
private MemoryCacheOptions options;
//强引用
private LruCache<String, Bitmap> mMemoryCache;
//软引用
private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;
/**
* Create a instance by default config
*/
public LRUBitmapMemoryCache() {
options = new MemoryCacheOptions.Builder()
.setmMaxCacheCount(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHECOUNT)
.setmMaxCacheSize(DefaultConfig.MemoryCacheDefaultOptions.MAXCACHESIZE)
.setmUseCache(DefaultConfig.MemoryCacheDefaultOptions.USECACHE)
.build();
initializeCache();
}
/**
* set a options as you set
*
* @param defaultOptions
*/
@Override
public void setOptions(MemoryCacheOptions defaultOptions) {
this.options = defaultOptions;
}
private void initializeCache() {
if (options == null) {
throw new VinciException("LRUBitmapMemoryCache#options is null");
}
if (options.getmMaxCacheSize() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache size is o");
}
if (options.getmMaxCacheCount() == 0) {
throw new VinciException("LRUBitmapMemoryCache#max cache count is o");
}
MLog.d(TAG, "maxSize:" + options.getmMaxCacheSize() + " maxCount:" + options.getmMaxCacheCount());
mMemoryCache = new LruCache<String, Bitmap>(options.getmMaxCacheSize()) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in kilobytes rather than
// number of items.
return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
}
@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
// TODO Auto-generated method stub
super.entryRemoved(evicted, key, oldValue, newValue);
if (oldValue != null) {
// the allocation is full, move bitmap to soft reference
mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
testLog("entryRemoved to mSoftCache:" + key);
}
}
};
mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
options.getmMaxCacheCount(), 0.75f, true) {
private static final long serialVersionUID = 6040103833179403725L;
@Override
protected boolean removeEldestEntry(
Entry<String, SoftReference<Bitmap>> eldest) {
if (size() > options.getmMaxCacheCount()) {
testLog("removeEldestEntry true");
return true;
}
testLog("removeEldestEntry full");
return false;
}
};
}
@Override
public Bitmap get(String key) {
testLog("get:" + key);
if (TextUtils.isEmpty(key)) {
return null;
}
Bitmap bitmap;
// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);
if (bitmap != null && !bitmap.isRecycled()) {
// LRU : refresh this bitmap position
mMemoryCache.remove(key);
mMemoryCache.put(key, bitmap);
testLog("get mMemoryCache");
return bitmap;
}
}
// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null && !bitmap.isRecycled()) {
// move bitmap to mSoftCache
mMemoryCache.put(key, bitmap);
mSoftCache.remove(key);
testLog("get mSoftCache");
return bitmap;
} else {
// is recycled
mSoftCache.remove(key);
}
}
}
return null;
}
@Override
public boolean isExist(String key) {
if (TextUtils.isEmpty(key)) {
return false;
}
Bitmap bitmap;
// get bitmap from mMemoryCache
synchronized (mMemoryCache) {
bitmap = mMemoryCache.get(key);
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}
// get bitmap from mSoftCache
synchronized (mSoftCache) {
SoftReference<Bitmap> bitmapReference = mSoftCache.get(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
if (bitmap != null && !bitmap.isRecycled()) {
return true;
}
}
}
return false;
}
@Override
public Bitmap remove(String key) {
// remove bitmap from mMemoryCache
Bitmap bitmap;
synchronized (mMemoryCache) {
bitmap = mMemoryCache.remove(key);
}
// remove bitmap from mSoftCache
synchronized (mSoftCache) {
if (bitmap != null && !bitmap.isRecycled()) {
mSoftCache.remove(key);
} else {
SoftReference<Bitmap> bitmapReference = mSoftCache.remove(key);
if (bitmapReference != null) {
bitmap = bitmapReference.get();
}
}
}
return bitmap;
}
@Override
public void put(String key, Bitmap bitmap) {
if (bitmap == null || bitmap.isRecycled()) {
return;
}
testLog("put:" + key);
// thread synchronize
synchronized (mMemoryCache) {
mMemoryCache.put(key, bitmap);
}
}
@Override
public void clear() {
synchronized (mMemoryCache) {
mMemoryCache.evictAll();
}
synchronized (mSoftCache) {
mSoftCache.clear();
}
}
private final boolean ISDEBUG = false;
private void testLog(String str) {
if (ISDEBUG) {
MLog.e(TAG, str);
}
}
}
这个缓存是基于LRU算法的缓存机制,LRU即最久未使用算法,当内存不足时将最久未使用的对象放入软引用区,当内存不足时可以及时释放。
[项目的GitHub地址](https://github.com/CJstar/Vinci)
发表评论
-
Android开发第一步
2013-07-10 20:21 228首先得搭建开发环境,地址:http://cj-star.it ... -
android打开模拟器提示emulator-arm.exe已停止工作
2012-12-04 10:35 579最近遇到一个模拟器打开问题,解决办法: 勾选use host ... -
Android获取视屏的缩略视图和图片的缩略视图
2012-11-27 17:45 257//获取视屏的缩略视图path为视屏路径 Thumbna ... -
Android获取SD卡路径方法
2012-11-27 17:45 216public String getSDPath(){ ... -
android开发中ListView的妙用之:下拉刷新与到底部载入更多源码
2012-09-13 09:28 4372今天项目也快结束了,就写篇博客吧,记录一下我对ListView ... -
java int类型的数据转换为byte[]类型的数据
2012-09-11 17:25 1023public static byte[] int32ToB ... -
打开模拟器遇到PANIC: Could not open: E:\Program Files (x86)\myeclipse\MyEclipse 9\
2012-02-15 22:01 554这问题出在你的SDK的环境变量没有设置正确,你将环境变量中的S ... -
在eclipse中搭建android开发平台
2012-02-15 21:27 428从今天起,打算好好写一下自己的技术博客,就从androi ... -
android获取本机号码
2012-02-04 12:48 2151private String getPhoneNumbe ... -
android如何发送短信
2012-02-04 12:42 344首先必须有接收方的号码: String number; 然 ...
相关推荐
Android图片加载&使用介绍
Android图片加载框架类似Glide
android 图片加载优化 解决的OOM异常
Android 强大的图片加载类 图库效果,详细的Handler操作案例。
很简单的android图片加载框架Picasso
Android 图片加载ImageLoader 特点: 先从缓存中取图,有--->返回 无--->去SDCard中取图 --->有---->存入缓存---->返回 --->无---->网络下载---->成功---->存入SDCard和缓存--->返回 ---->失败----->默认图
Android 图片加载和网络图片轮播图超好用的可以加载本地图片和网络图片的轮播图
android图片加载库Picasso
android图片加载框架imageloader源码+demo,配置好的,导入就可以直接运行
主要为大家详细介绍了Android图片加载框架的简单设计,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Android图片加载框架之Picasso非常好的图片加载缓存库 , 博客地址:http://blog.csdn.net/dickyqie/article/details/62233744
Fresco是Facebook开源Android平台上一个强大的图片加载库。
在我们平时加载图片的时候,我们经常会遇到这样一个需求,那就是当图片正在加载时应该呈现正在加载时的图像,当图片加载失败时应该呈现图片加载时的图像,当我们重新加载这张图片时,应该呈现重试时图像,直到这张...
一个Android库管理图片和它所使用的内存。
ImageLoader 具有某些新特性的图片加载框架
NULL 博文链接:https://1002878825-qq-com.iteye.com/blog/1610006
图片加载是Android开发中最最基础的功能,为了降低开发周期和难度,我们经常会选用一些图片加载的开源库
Android 图片异步加载 加载网络图片
Android异步加载的框架,优化了AsyncTask,简单易上手