目录
背景
某次新功能迭代,经部署后发现Pod出现OOM,报错日志为:
java.lang.OutOfMemoryError: Metaspace
分析
JVM启动项
因为是在容器部署的,首先检查了下startup.sh启动脚本,发现设置JVM参数的时候显式的设置了metaspace大小为Pod总内容大小的1/20。算下给Pod分配的总内存是4G,那么mataspace的总大小是200M,很快就溢出了。
limit_in_bytes=$(cat /sys/fs/cgroup/memory/memory.limit_in_bytes)
if [ "$limit_in_bytes" -ne "9223372036854771712" -a "$limit_in_bytes" -ne "9223372036854775807" ]; then
limit_in_megabytes=$(expr $limit_in_bytes \/ 1048576)
heap_size=$(expr $limit_in_megabytes \* 4 \/ 7)
mate_size=$(expr $limit_in_megabytes \* 1 \/ 20)
export JAVA_OPTS="-Xmx${heap_size}m -Xms${heap_size}m $JAVA_OPTS -XX:MaxMetaspaceSize=${mate_size}m -XX:MaxDirectMemorySize=${mate_size}m -XX:CompressedClassSpaceSize=${mate_size}m -XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/envuser/logs -XX:ErrorFile=/home/logs/hs_err_%p.log"
echo JAVA_OPTS=$JAVA_OPTS
fi
经查找相关资料发现metaspace如果不设置,默认是可以动态调整的,所以这里做的第一个修改就是将JVM的参数更改掉
if [ "$limit_in_bytes" -ne "9223372036854771712" -a "$limit_in_bytes" -ne "9223372036854775807" ]
then
limit_in_megabytes=$(expr $limit_in_bytes \/ 1048576)
heap_size=$(expr $limit_in_megabytes \* 3 \/ 4)
export JAVA_OPTS="-Xmx${heap_size}m $JAVA_OPTS"
echo JAVA_OPTS=$JAVA_OPTS
fi
代码逻辑优化
因为这个版本引入了一些文件和二进制流处理的逻辑,另外一个很重要的原因就是排查代码,发现代码中有些操作了InputStream和ReadBuffer后没有关闭的情况,也将这块逻辑进行了调整优化。
处理结果
经过前两部初步处理后没有明显观察到metaspace溢出的情况了。
深层分析
待进一步补充