记录一个非常低级的错误导致的java应用一直fullgc的问题;根本原因就是HashMap的key使用姿势不对
1. 问题记录
先捞出有问题的现场代码,之前写了一个简单的工具类,用来保存两个元素,简单的模拟了一下Guava的实现姿势
1 | public final class ImmutablePair<L, R> { |
最开始主要是由于某些地方返回结果时,需要返回多个对象,而java并不能像python那么友好的支持这个功能,所以写了上面这个简单的工具类,对返回结果进行一个简单的封装
距离这个工具类写完之后一两个月的时间,突然有个临时需求场景,对于每次的请求,需要做一个简单的内存过滤;如果这次请求距离上次超过5s, 则直接不处理;否则才接受;于是写了下面这段代码
1 | private Map<ImmutablePair<String, Integer>, Long> cache = new HashMap<>(); |
直接看上面这段代码,貌似没有啥问题,然后愉快的跑起来;但是一段时间之后呢?内存疯狂的上涨,且一直在fullgc
简单的测试下上面方法,发现过滤逻辑一直都没有生效
HashMap根据Key获取Value的方式,主要是根据key的hashcode
去定位对应的元素位置,然后通过equals
方法判断找到的对象是不是我们预期的目标
因为我们最上面的ImmutablePair
类,没有覆盖这两个方法,所以是默认的,这个时候equals
方法和==
是等效的,主要是判断是否为同一个引用,所以上面的key每次都是重新创建对象,当然和缓存的不一致,从而导致每次都不命中,一直往Map里面塞数据,但是又回收不了,所以导致了这个问题
2. 小结
- 对于HashMap的key对象,务必保证是重写了
equals
和hashcode
方法的 - 用内存做缓存时,使用guava的cache并设置上限,相对而言是更加优雅的方式
- 使用HashMap时,尽量指定Map的初始化容量,否则可能出现频繁的扩容;其次就是最好能保证下HashMap的个数,毫无限制的情况下,说不准哪天就暴雷了
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
3. 扫描关注
一灰灰blog
知识星球