应该是从java G1开始就没有具体的老年代了。
但是在工作中由于使用的是老的GC形式。还是出现了这个问题。下面记录一下自己发现问题,解决问题的方法。
- 首先下载生产环境dump
- 使用jvisual 打开dump。老年代持续过高,可能有两个原因
- 大对象过多。如果对象太大,会直接分配到老年代
- 代码中有leak,造成资源无法回收。
- 拿到dump后,看到了有很多 byte 数组过大。看了一下内容,是上传附件的内容导致的。下面是第一版上传附件的后端代码。
由于需要调用其他服务,所以要把request格式进行转化,不能直接透传。所以用到了ByteArrayResource。应该是转化成了这个地方转化的byte数组。没有及时的进行回收。
开始解决
方案一:
- 最开始打算查看http协议,直接用outputstream,直接写需要的数据。主要为了,不用读取字节数组。然后通过stream copy 减少内存使用。后来写了一点就放弃了。有点麻烦。
- 然后看了一下源代码,发现使用的是ByteArrayResource。我想直接使用其他的Resource代替就好了,应该有已经实现的这种累。然后找到了InputStreamResource。替换了以后,发现报错.do not use InputStreamResource if a stream needs to be read multiple times
- 我查看了一下代码,我应该没有使用InputStreamResource读取过内容。后来找了一篇帖子发现,AbstractResource读取长度的时候会调用inputSteam,代码如下。
知道问题,然后避免读取inputStream就好了。重写 contentLeagth 方法。试了一下果然好用。
然后打开-XX:+PrintGC 。发现内存果然会减少。
实际效果,还得等到上线以后才可以查看效果。