前几天面试,被问到了一个问题,如果当前有数亿条记录,但是缓存最多放100万条记录,怎么保证缓存很好的被利用(大概是个这个意思,具体的问题记得不太清楚了).当时一下没回答出来,就随便说了一下,利用类似java虚拟机的垃圾回收算法来实现缓存的回收.
回来后苦思冥想,相出一个简单的方案.
首先,利用HaspMap(考虑用ConcurrentHashMap,并发下这个map效率高)来存放缓存对象,每次被缓存的对象用一个CacheObject封装.封装的目的主要是给这个个缓存对象添加一些属性信息,如果被命中的次数,过期的之间之类的.
public class CacheObject {
private Object cache;//被cache的对象
private int hit;//命中次数
private long expire;//过期时间
public CacheObject(Object object){
this.cache = object;
}
public Object getCache() {
return cache;
}
public void setCache(Object cache) {
this.cache = cache;
}
//这里我就不实现如何生成hashCode的策略了
public Integer getHashCode(){
return null;
}
public int getHit() {
return hit;
}
public void setHit(int hit) {
this.hit = hit;
}
public long getExpire() {
return expire;
}
public void setExpire(long expire) {
this.expire = expire;
}
然后在建立几个LinkedList对象,来模拟jvm回收中的分代机制.下面是jvm分代示意图:
Heap = {Old + NEW = { Eden , from, to } }
JVM
内存模型中分两大块,一块是
NEW Generation,
另一块是
Old Generation.
在
New Generation
中,有一个叫
Eden
的空间,主要是用来存放新生的对象,还有两个
Survivor Spaces(from,to),
它们用来存放每次垃圾回收后存活下来的对象。在
Old Generation
中,主要存放应用程序中生命周期长的内存对象,还有个
Permanent Generation
,主要用来放
JVM
自己的反射对象,比如类对象和方法对象等。
垃圾回收描述:
现在我们用LinkedList对象来模拟JVM中的Old,Eden , from, to对象,来实现我们的缓存垃圾回收.新被添加进缓存的对象(CacheObject)的引用都被存放在Eden对象的队列的头部里,如果要回收缓存对象时,从Eden队列的尾部开始扫描.如果扫描时发现这个CacheObject没有被命中,就把这个CacheObject对应在缓存中的数据删掉,并把这个CacheObject从Eden中删掉;如果发现这个CacheObject被命中了,就把它挪到from的队列的首部.最后命中次数多的CacheObject会被移动到Old队列里面.
回收的时候我们可以模拟JVM里面的回收分级,例如:0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾.
这里的Old,Eden , from, to在垃圾回收的时候都是FIFO模式,新的对象放队首,回收的时候从队尾开始回收.
我这里就给个简单的思路,希望大侠们指正.
===========
原来的写文章时候对缓存的写法理解不够深刻,其实没必要把算法搞的如此复杂,只需要用一个链表实现就好.然后再用以下清理策略来清理.
1.设置一个自动清理的线程,定时启动检查.
2.设置一个缓存数目最大值,超过这个最大值就启动清理(优先清理命中率低的).
3.设置一个最大超时时间,超过这个时间,必须回收此缓存.
4.设置一个清理比率a,每次清理到缓存数目 最大值*(1-a) 就停止清理.
5.命中一次就把此缓存丢到链表的尾部,每次新的元素都丢到链表的尾部.
6.清理时,先遍历整个缓存,把超时的全部清理掉.如果清理完超时的还不够,就从头部开始往后删除元素超过范围的元素.(因为是链表,直接算出要删除多少条数据,然后把头部直接指向那条记录就完成了删除,效率很高)
分享到:
相关推荐
对象缓存
该方法首先构建了一个混合云部署框架,包含预报和云缓存回收两个基本模块,根据统一的成本模型和改进的MLP自适应调整将窗口大小参数化,按照窗口参数或必需的缓存空间选择出一组在缓存中最近最少使用(LRU)的对象。...
将获得的数据以对象的形式缓存到本地,本例中实现了: 1.将登陆用户名和密码缓存到本地 2.将缓存的用户名和密码取出显示 本例仅供参考
Ehcache 整合Spring 使用页面、对象缓存
Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提供动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的...
在场景缓存中选中对象,将对象属性以气泡的形式显示。
统计缓存大小(查看java对象所占的内存大小).
hibernate的缓存机制和session对象的产生方式案例,里面写到session的两种产生方式,和hibernate的缓存机制:一级缓存、二级缓存、查询缓存
1、OSCache是什么? 2、OSCache的特点 3、有关“用OSCache进行缓存对象”的研究
强引用缓存不会轻易被回收,来保存常用数据,不常用的资源放入软引用缓存中。 对于硬引用和软引用的介绍: ⑴强引用(StrongReference) 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会...
phpFastCache是一种高性能,分布式的对象缓存系统,旨在用于通过缓存减轻数据库负载来加速动态Web应用程序
数据库优化,详细介绍缓存对象与数据,一种优化手段。
企业级SSD缓存设计的思考.pptx
企业级SSD缓存设计的思考.pdf
Kashmir是一个Ruby DSL使得序列化和缓存对象易如反掌
关于缓存的一点心得 1、缓存有页面缓存与数据缓存,页面缓存就是把显示的页面生成一个文件,数据缓存就是把数据生成一个文件,都有一个更新缓存的间隔时间,判断文件的修改时间或者生成时间的时间邮戳加上间隔时间的...
ASP.NET内置对象,应用程序配置和缓存资料文档
关于缓存的一些资料关于缓存的一些资料关于缓存的一些资料关于缓存的一些资料关于缓存的一些资料
纯as3代码实现对象缓存,对应频繁需要创建和销毁的对象,采用一个缓存队列,保存一定数量的对象,当需要的时候从队列里取出,不再需要的时候交给缓存池。