前几天面试,被问到了一个问题,如果当前有数亿条记录,但是缓存最多放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.清理时,先遍历整个缓存,把超时的全部清理掉.如果清理完超时的还不够,就从头部开始往后删除元素超过范围的元素.(因为是链表,直接算出要删除多少条数据,然后把头部直接指向那条记录就完成了删除,效率很高)
分享到:
相关推荐
- **1.1.1.3 使用常量避免创建对象**:例如,`new Decimal(0)`这样的代码会导致小对象频繁创建及回收。正确的做法是使用`Decimal.Zero`这样的常量,这可以避免不必要的对象创建和销毁开销。 - **1.1.1.4 使用...
在C#中,不必要的对象创建会增加垃圾回收的压力,从而影响应用程序的整体性能。以下是一些避免对象创建的建议: - **减少临时对象的创建**:例如,在循环中避免重复创建相同类型的临时对象。 - **复用对象**:当...
Java工程师面试题大全及答案,这是一份专为准备Java面试者精心整理的资源,涵盖了大量知名企业的面试问题。这份资料对于那些希望在Java开发领域深入发展或正在寻找新工作机会的程序员来说,无疑是一份宝贵的复习材料...
- 如何在实际工作中利用Kafka处理大量实时数据流。 3. **字符串处理算法题** - 一般考察字符串操作的基本能力和算法优化技巧。 综上所述,字节跳动的大数据面试题覆盖了从Hadoop生态系统的基础知识到高级应用的...
12. **性能优化**:对于高并发的投票场景,系统需要进行性能优化,如缓存策略、负载均衡、数据库查询优化等,以确保在大量用户访问时仍能保持高效运行。 这个JSP企业电子投票系统不仅涵盖了多种IT技术的应用,还...
不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。 要试着运行这些示例,需要先复制本...
不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。 要试着运行这些示例,需要先 复制本代码...
23. **对象复用**:如对象池技术,通过预先创建和缓存对象,避免频繁创建和销毁带来的性能损失。 24. **零拷贝**:在数据传输中,通过避免不必要的数据复制,提高I/O操作的效率,常见于网络传输和文件操作。 25. *...
- **自动垃圾回收机制**:自动管理内存,减少内存泄漏的风险。 #### 17. WebService的创建方法 - **使用WSDL.exe工具**:生成Web服务描述文件。 - **使用Visual Studio的Add Web Reference功能**:添加对现有...