基于年纪和成本(Age & Cost)的缓存替换(cache replacement)机制
一、客户端的缓存与缓存替换机制
客户端的资源缓存:
在客户端游戏中,通常有大量的资源要处理,这些可能包括贴图、动作、模型、特效等等,这些资源往往存在着磁盘文件->内存(->显存)的数据通路,因为从磁盘文件读入内存是一个昂贵的的操作,所以很多客户端中的处理方法是放入一个缓存,当读入一个文件到内存后,就在内存中为他暂时保留一段时间,下次在读入这个文件就不用重复从磁盘读了,这种优化带来了客户端效率的极大提升,比如在一个有上百玩家的场景,可能我们用的玩家模型资源都是一个,只是贴图不同而已,如果使用缓存,那么你只需要从磁盘读取一次玩家模型的文件,而如果不使用,你可能要反复读取上百次,IO操作的低效会让用户很卡。
缓存替换:
然而我们用户的内存是有限大的,如果我们把每个资源都读进去保留而不释放,游戏就会越来越吃内存,一个典型的大象网游的资源可能几个G,最坏的情况用户读入了所有资源到缓存而不释放,那么也会因为内存不够用而崩溃。所以这里就通常要选择一些缓存替换机制:即动态的释放和加入资源到缓存,有进有出,但是要保证尽量让用户IO操作减少,一种最乐观的情况是,存在缓存中的资源恰好是用户使用的最多的资源,使用较少的会被使用多的交换出去。这模仿了CPU的cache机制。
二、现有的一些缓存替换机制:
基于CPU和操作系统的一些经典的cache replacement算法,客户端的资源缓存替换机制有以下一些做法:
1.懒人型,最简单的。就是没什么交换算法,只管读入缓存,然后只是定期的或发现缓存太大时一次性的清空缓存重来,这种在清空后会经历一段加载资源的顿卡,突然发现目前我们游戏的机制就是这样的,尴尬。。。但是这可能符合简单粗暴实用的原则。
2.LRU算发:大名鼎鼎的算法,当出现替换时,总是替换那个 上次使用时间距离限制最远的那个,这种算法认为最近使用的就是最长使用的,这种算法被多数体系结构使用,不过在某些极端情况下会导致thrash(内存的剧烈颠簸),比如说当一段时间内需要加载的东西过多时,而加载的资源呈有序重复序列时可能缓存会被一遍遍的清空。
3.MRU算法:它与LRU对应,但是它总是交换出最近使用的那个,这个倾向于保存最老的那个,听起来很奇怪,但是它往往不单独使用,通常配合LRU使用,当LRU出现thrash时转到MRU算法会有所帮助
三、基于Age和Cost 的算法:
今天看到了一种算法基于Age和Cost,似乎对客户端的缓存替换研究的更加到位一些,这种算法梗概如下:
1.Age:
为每个缓存保存一个32位的Age值初始为00000000(也就是第一次载入缓存时)(文档暂以8位代替),,每当hit一次,当前的最低位置1,每个计数区间(或每一帧)这个Age左移一位,例如某个资源在几帧内Age的变化
frame1:00000001(used)
frame2:00000011(used)
frame3:00000111(used)
frame4:00011100(not used)
frame5:00111000(not used)
根据当前的age,可以算出Age percentage Cost APC=1的数量/总的位数
APC越高说明这个资源近段时间是越有用的,替换时选择APC低的替换
基于Age的算法更加精确的得出了最近一段时间内资源的使用率,找出比lru更合理的替换,
2.Age扩展算法:
上面的每一步是按照帧来算的,实际使用中没帧来统计肯定是有点过了,可以按照一定时间片来统计,在一定时间片内可能一个资源回被用到n次,因此扩展的Age算法就单纯的标记1改为标记n,即这个统计区间内被用到的次数,如上例
time1:00000005(used 5 times)
time2:0000005A(used 9 times)
time3:000005A1(used 1 times)
time4:0005A100(not used)
time5:005A1000(not used)
这样APC=各位的值相加/最大的可能值
例如某个模型资源在上一段时间内被100个玩家引用,那么替换他的代价就明显要高很多,Age的扩展方法考虑的引用的频次
3.Age&Cost:
在实际的操作中,有些资源的替换成本是非常大的,例如从硬盘读入一个10m的贴图显然比读入一个100k的贴图成本大很多,所以替换时不能相同对待,这里考虑的成本记为relative cost(RC),算法中将最终的缓存替换成本TC=APC*RC,这样来综合考虑,通常将APC取值区间规整为0-1,而将rc规整为 1-10(算法作者认为载入文件的时间成本权重更大)。这样对不同的资源为它赋值不同的载入时间成本RC,再乘以上面的Age算法中的APC(引用频率成本),综合得出了它的缓存替换成本。一种比较简单的rc的赋值可以用它的文件大小来自动赋值。
几个例子:
APC RC TC
1 10 10 这说明这个文件的替换成本非常大,主要是文件比较大,同时它引用的频率特别高,这种资源基本上不会轻易从缓存中替换出来
0.2 8 4 这个文件很大,但是引用频率还很低,所以替换程度是中等的
1 5 5 文件很小,说明载入很快,但是引用频率很高,所以可以替换出来(因为再载入的成本低),也可以不替换出来,中等的
0.1 10 1 这个文件很大,载入很慢,但是引用很少,也就是说内存中存在一个很占地方但是几乎不怎么用的资源,值得替换出来,节省空间,因为不常用再次载入就算费时也值得
比如我们的游戏中开场有一个非常大的贴图资源,用于登录界面,它最开始有60M,(游戏中一般的贴图在几百K以下),而它在游戏中不会再被用到,现有的算法这个很大的资源会一直占在缓存里,用户内存被无故吃了很多,但是应用本算法,它的RC在游戏中可以达到上限10,但是APC基本上是下限,也许0.01,所以他的TC可能只有0.1,将登陆之后很快的时间内被从内存中释放出来。
赶紧利用这个算法节省一下我们的内存
基于年纪和成本(Age & Cost)的缓存替换(cache replacement)机制的更多相关文章
- 搜索引擎的缓存(cache)机制
		什么是缓存? 在搜索领域中,所谓缓存,就是在高速内存硬件设备上为搜索引擎开辟一块存储区,来存储常见的用户查询及其结果,并采用一定的管理策略来维护缓存区内的数据.当搜索引擎再次接收到用户的查询请求时,首 ... 
- HTTP请求的缓存(Cache)机制
		原文地址:http://small.aiweimeng.top/index.php/archives/58.html 先来一张图: ####下面简单的来描述一下HTTP Cache机制: 当资源资源第 ... 
- 一个基于STSdb和fastJson的磁盘/内存缓存
		一个基于STSdb和fastJson的磁盘/内存缓存 需求 业务系统用的是数据库,数据量大,部分只读或相对稳定业务查询复杂,每次页面加载都要花耗不少时间(不讨论异步),觉得可以做一下高速缓存,譬如用n ... 
- 缓存篇(Cache)~大话开篇
		回到占占推荐博客索引 闲话杂淡 想写这篇文章很久了,但总是感觉内功还不太够,总觉得,要写这种编程领域里的心法(内功)的文章,需要有足够的实践,需要对具体领域非常了解,才能写出来.如今,感觉自己有写这种 ... 
- 从Java视角理解CPU缓存(CPU Cache)
		从Java视角理解系统结构连载, 关注我的微博(链接)了解最新动态众所周知, CPU是计算机的大脑, 它负责执行程序的指令; 内存负责存数据, 包括程序自身数据. 同样大家都知道, 内存比CPU慢很多 ... 
- Kafka元数据缓存(metadata cache)
		经常有人问的一个问题就是:Kafka broker到底是不是无状态的?网上有这样的说法: 正常情况下consumer会在消费完一条消息后线性增加这个offset.当然,consumer也可将offse ... 
- yii中缓存(cache)详解
		缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: 1 ... 
- Cache replacement policies 缓存实现算法
		Cache replacement policies - Wikipedia https://en.wikipedia.org/wiki/Cache_replacement_policies Cach ... 
- yii中缓存(cache)详解 - 彼岸あ年華ツ
		缓存是用于提升网站性能的一种即简单又有效的途径.通过存储相对静态的数据至缓存以备所需,我们可以省去生成 这些数据的时间.在 Yii 中使用缓存主要包括配置和访问缓存组件 . 内部方法 一.缓存配置: ... 
随机推荐
- C# ashx生成的验证码
			public void ProcessRequest(HttpContext context) { context.Response.ContentType = "image/jpeg&qu ... 
- webform  repeater
			repeater:由模板构成,解析后模板就不存在了 需要指定数据源进行数据绑定 List<Fruit> list = new FruitDA().Select(); ... 
- hdu 2190
			//hdu2190 水题 题意是给一个n*3的教室,用1*1,2*2的砖去铺满,有多少种铺法,一开始没发现这个规律,想了一下,应该是递归. #include <iostream> usi ... 
- (转)PHP 的 __FILE__ 常量
			今天碰到了PHP的常量__FILE__的问题了. 在网上查了一下.总结了以下规律. dirname(__FILE___) 函数返回的是脚本所在在的路径. 比如文件 b.php 包含如下内容: < ... 
- Ext江湖笔记:JavaScript基本知识点
			1.基本对象:Number,String,Date,Array,Error,RegExp,Math,Boolean ps:本人基本使用java写代码,常常写出Number n = new Number ... 
- 获取subview
			通常我们在view层级里面对subView的操作可以通过两种方式:1.保留一个subview的引用,然后在类中通过该引用对该subview进行操作,但是要注意在适当的位置添加内存维护的代码,退出前手动 ... 
- Objective-C学习篇10—NSDate与NSDateFormatter
			NSDate NSDate 时间类,继承自NSObject,其对象表示一个时间点 NSDate *date = [NSDate date]; NSLog(@"date = %@", ... 
- URAL 1008 - Image Encoding(bfs坑爹题)
			坑爹题,两种输入输出互相交换,裸bfs #include <stdio.h> #include <string.h> typedef struct { int x; int y ... 
- IOS学习之十七:Grand Central Dispatch(GCD)编程基础
			IOS学习之十七:Grand Central Dispatch(GCD)编程基础 有过编程经验的人,基本都会接触到多线程这块. 在java中以及Android开发中,大量的后台运行,异步消息队列, ... 
- AtomicInteger小小的理解
			这里仅仅是验证多线程环境下,AtomicInteger的安全性. 通过源码不难发现两点: 1.value属性是volatile修饰 2.使用了unsafe的CAS操作 通过上述两点,实现非阻塞同步(乐 ... 
