当前位置: 首页>后端>正文

内存管理——缓存与分代回收的矛盾

缓存的目标是让热数据(频繁被访问的数据)能够留在内存,以便提高缓存命中率。而JVM垃圾回收(GC)的目标是释放失去引用的对象的内存空间。两者目标看上去相似,但细微的差异让两者在高并发的情景下很难共存。缓存的淘汰会产生大量的内存垃圾,使Full GC变得非常频繁。这种矛盾其实不限于客户端,而是所有JVM堆内缓存共同面临的问题。下面我们仔细分析一个场景:
随着请求产生的数据会不断加入缓存,QPS较高的情形下,Young GC频繁发生,会不断促使缓存所占用的内存从新生代移向老年代。缓存被填满后开始采用Least Recently Used(LRU)算法淘汰,冷数据被踢出缓存,成为垃圾内存。然而不幸的是,由于频繁的Young GC,有很多冷数据进入了老年代,淘汰老年代的缓存,就会产生老年代的垃圾,从而引发Full GC。

可以看到,正是由于缓存的淘汰机制与新生代的GC策略目标不一致,导致了缓存淘汰会产生很多老年代的内存垃圾,而且产生垃圾的速度与缓存大小没有太多关系,而与新生代的GC频率以及堆缓存的淘汰速度相关。而这两个指标均与QPS正相关。因此堆内缓存仿佛成了一个通向老年代的垃圾管道,QPS越高,垃圾产生越快!
因此,对于高并发的缓存应用,应该避免采用JVM的分带管理内存,或者可以说,GC内存回收机制的开销和效率并不能满足高并发情形下的内存管理的需求。由于JVM虚拟机的强制管理内存的限制,此时我们可以将对象序列化存储到堆外(Off Heap),来达到绕开JVM管理内存的目的,例如Ehcache,BigMemory等第三方技术便是如此。或者改动JVM底层实现(类似之前淘宝的做法),做到堆内存储,免于GC

来自 https://zhuanlan.zhihu.com/p/28522487


https://www.xamrdz.com/backend/3br1925158.html

相关文章: