问题定位:
最近奉命解决游戏中始终在的内存不够的问题,最终定位到底层的缓存机制应用的是google提供的ConcurrentLinkedHashMap做数据缓存的。
简略介绍下ConcurrentLinkedHashMap,这是一个基于LRU策略的缓存,说白了就是热点数据缓存,反对设置最大缓存个数,监控到缓存数量超过最大值后会根据权重策略让数据过期。
剖析:
依据ConcurrentLinkedHashMap的个性,咱们这边揣测出玩家数据在被加载放到缓存后,如果缓存没有超过设置的最大值,则这些数据会始终放在缓存中;正当上来说这些没被应用的数据,在闲暇肯定工夫后是能够被革除的,而不必始终占据在缓存中。
然而ConcurrentLinkedHashMap并没有在数据闲暇肯定工夫后主动清空数据的机制,因此想要解决这个缓存问题,必须应用一个既反对基于缓存个数大小回收,又反对基于闲暇工夫回收的第三方组件,而在多番理解和数据查证后最终抉择了Caffeine。
Caffeine是什么
Caffeine 是一个高性能的 Java 缓存库,缓存和 Map 之间的一个基本区别在于缓存能够依据回收策略回收存储的数据。此策略间接影响缓存的命中率 ,而缓存命中率额也是缓存库的一个重要特色。Caffeine 因应用 Window TinyLfu 回收策略,提供了一个近乎最佳的命中率。
咱们能够看到官网提供的几张性能截图
场景1:8个线程读,100%的读操作
image-20201101101125396
场景二:6个线程读,2个线程写,也就是75%的读操作,25%的写操作
image-20201101101157144
场景三:8个线程写,100%的写操作
image-20201101101219341
能够分明的看到Caffeine效率显著的高于其余缓存。
将Caffeine替换掉ConcurrentLinkedHashMap,接下来就是要验证下,是否反对基于闲暇工夫回收,进而解决咱们游戏中的内存问题了。
Caffeine和ConcurrentLinkedHashMap的应用比照
操作流程:本地起两个服,一个缓存底层应用的是ConcurrentLinkedHashMap,另一个底层应用的是Caffeine,Caffeine服设置的数据操作闲暇工夫是1分钟,起服后别离应用jvisualvm记录起始内存曲线,截图保留,之后启动2000个机器人模仿登陆,登陆后再过1分钟别离手动调用FullGC,查看jvisualvm记录的内存曲线,并查看堆dump记录。
【ConcurrentLinkedHashMap服】起始内存
image-20201101103752470
【ConcurrentLinkedHashMap服】2000个机器人模仿登陆后下线,并手动调用FullGC后查看内存曲线
image-20201101104016330
咱们能够看到堆内存并没有回到原来的曲线。
查看堆dump记录
image-20201101104341454
能够看到该对象的实例数没有降落到0。
【Caffeine服】起始内存
image-20201101105100049
【Caffeine服】2000个机器人模仿登陆后下线,并手动调用FullGC后查看内存曲线
image-20201101105137160
这里看到内存曲线回到了起服时的模样,再查看堆dump记录
image-20201101104640103
能够看到,对象实例个数也被回收了,那么这里残余的实例个数1是怎么回事,这里波及到Caffeine的原理,留个悬念,等下篇文章再解说,有趣味关注一波,前期筹备写个Caffeine系列教程。
通过以上比照,能够得出Caffeine具备“主动”清空缓存过期数据的机制,并且能够解决咱们游戏中始终存在的内存问题。
总结
目前对Caffeine的替换曾经提交到线上运行了,因为目前网上相干教程偏少,因此后续筹备写一系列Caffeine相干的文章进行解密,有趣味的关注一波。
img