目录java
序:使用java的Map作缓存,你是否考虑过容量致使的OOM问题,是否考虑命中率对性能的影响??mysql
应用系统开发中,咱们常常会使用redis,memcache等第三方框架作缓存的解决方案,有的时候咱们的需求以及应用场景并非那么复杂,并且交付日期已经秒计了。咱们怎么敢在现有的应用中引入第三方框架,火都把头顶烧秃咯。这个时候怎么办,绩效啊,年终奖啊。redis
可能大部分人使用缓存都仅仅是取和存操做,可是呢!若是对计算机操做系统有所了解,其实不用看redis的配置文件就知道要考虑容量的问题。好比操做系统中的页面调度的各类FIFO,LRU算法都是为了提升命中率。一样咱们在应用中使用缓存也应该考虑命中率和容量问题。尤为是咱们使用Java的map作简单的缓存,更是应该考虑。算法
女神:容量是吗?说的那么高大上,不就new的时候指定一下容量嘛,这么简单sql
new HashMap<Integer, Byte[]>(100);
intsmaze:您好,你能够尝试往map里面添加101个元素,而后遍历map看看遍历的数据个数是100仍是101,HashMap内部有一个数组,会自动扩容的亲。api
女神:哎呀,确实。那么我就把HashMap封装一下吧。数组
private Map<String,String> map=new HashMap<String,String>(); private int len; public intsmaze(int len) { this.len=len; } boolean put(String key,String value) { if(map.size()==len) { return false; } else { map.put(key, value); return true; } }
intsmaze:您好,这样确实解决了OOM问题,可是我有一个问题不知当讲不当讲,这样作的话,是否是put len次后,后面的数据都不会存储了,get的时候永远只能从get到钱len次的数据,其余的数据要走硬盘去读了?缓存
女神:是的,我把len的大小设置大一点,而后每隔一个小时清空一下map里面的值,不就好了,你为何要针对我啊?安全
intsmaze: 额,你这样也能够,可是要在前期花时间调试Map大小,选择一个合适的大小,并且每隔一个小时,mysql等存储都会面临大量的请求,容易引起缓存雪崩。并且若是最求性能的话,这里其实仍是有提升的,命中率的高低决定了性能的高低。多线程
女神: 那你想怎么样?咋滴啥?
intsmaze: 这个时候你能够了解一下FIFO,LRU等。若是你用过redis,你应该知道,不你可能知道,redis关于命中率三种策略(FIFO 、LRU、LFU)。因此咱们若是要使用Map作缓存,咱们也应该考虑一下命中率。后面编不下去了,直接讲这篇文章的重点吧。
WeakHashMap实现了Map接口,使用弱引用做为内部数据的存储方案。WeakHashMap是弱引用的典型应用,能够做为简单的缓存表解决方案。WeakHashMap会在系统内存范围内,保存全部表项目,一旦内存不够,在GC时,没有被引用的表项很快会被清除掉,从而避免系统内存溢出。
关于弱引用我就不讲啦,百度一大堆
Map<Integer, Byte[]> map = null; map = new WeakHashMap<Integer, Byte[]>(); for (int i = 0; i < 10000; i++) { Integer integer = new Integer(i); map.put(integer, new Byte[i]); } //-Xmx5M 这个时候发现没有OOM // -Xmx5M java.lang.OutOfMemoryError: Java heap space map = new HashMap<Integer, Byte[]>(10); for (int i = 0; i < 100; i++) { Integer integer = new Integer(i); map.put(integer, new Byte[i]); } //若是存放在WeakHashMap中的key都存在强引用,那么WeakHashMap就会退化为HashMap。 // -Xmx5M java.lang.OutOfMemoryError: Java heap space // at cn.intsmaze.collection.MapCase.testWeakHash(MapCase.java:119) map = new WeakHashMap<Integer, Byte[]>(); List list = new ArrayList(); for (int i = 0; i < 10000; i++) { Integer integer = new Integer(i); map.put(integer, new Byte[i]);// 若是你看不起我,你能够把这行注释,你将会发现姜仍是老的辣,内存溢出是WeakHashMap而不是List致使. list.add(integer); }
若是但愿在系统中经过WeakHashMap自动清理数据,尽可能不要在系统的其余地方强引用WeakHashMap的key,不然,这些key就不会被回收,WeakHashMap也就没法正常释放他们所占用的表项。
前面已经知道,使用WeakHashMap能够忽略容量问题,提高缓存容量。只是当容量不够时,不会OOM,内部数据会被GC回收。命中率好像没有办法,容我掉一片头发换来深度思考后给出方案。
使用WeakHashMap通常是全局变量,局部变量的应用场景应该没有吧。
观察WeakHashMap源码能够发现,它是线程不安全的,因此在多线程场景该怎么办嘞?
WeakHashMap<String, String> weakHashMapintsmaze=new WeakHashMap<String, String>(); Map<String, String> intsmaze=Collections.synchronizedMap(weakHashMapintsmaze);
就问你服不服。
一个ThreadLocal记录一个weakHashMap,良好的系统是不会不断的建立销毁线程的,而是有线程池进行维护,那么就用ThreadLocal吧。不懂,你能够先关注我,再去百度。
个人博客即将搬运同步至腾讯云+社区,邀请你们一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2mx7vvis5a80k