前言
前言:公司服务器从160g内存的windows虚拟机变更成了64g内存的centos7虚拟机,windows默认配置下未发现OOM异常(堆溢出),但是linux却在运行7天左右后会出现内存溢出,现学现用来通过修改JVM配置来解决这个问题.
JDK版本--1.8
ps:因为之前内存根本跑不满,觉得浪费,又因为windows经常更新就趁着机会一起换了
原本的服务器(内存好大,但是好卡!!!):
现在的服务器(双tomcat一起跑,还不会自己更新导致关机,还得是linux!):
原因分析
为什么会产生内存溢出?
内存溢出指的是程序在使用某一块内存区域时,存放的数据需要占用的内存大小超过了虚拟机提供的内存上限
Java内存空间主要包括这几个部分:方法区,堆内存,程序计数器,虚拟机栈,和本地方法栈。
- 方法区:主要存放已被加载的类信息,常量,静态变量等。(会溢出,根据虚拟机不同有不同的设计,Hotspot:jdk1.8:默认情况下只要不超过操作系统上限,可以一直分配)
- 堆内存:堆空间有三个需要关注的值,used total max
used 是指当前已经使用的堆内存
total 是java虚拟机已经分配的可用堆内存
max 是java虚拟机可以分配的最大堆内存
随着堆中的对象增多,当total可以使用的内存即将不足时,java虚拟机会继续分配内存给堆
如果堆内存不足,java虚拟机就会不断的分配内存,total值会变大,total最多只能与max相等,超过后将会OOM(OutOfMemoryError:Java heap space) - 程序计数器:每一个线程只存储一个固定长度的内存地址,不会发生内存溢出
- 虚拟机栈:Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配最大大小就会出现内存溢出(StackOverflowError)
- 本地方法栈:与虚拟机栈类似,主要为JVM使用到的Native方法服务(StackOverflowError)
具体原因分析
根据报错原因,实际问题是由堆内存溢出导致的OOM异常.
在Hotspot(jdk,open jdk)虚拟机中,jdk1.8没有手动设置的情况下,默认内存为总内存的1/4,所以原本的jvm内存应该是160/4=40g,而现有的内存大小为64g,所以默认大小应该为64/4=16g;并且还设置了双tomcat服务器,导致双服务器共用16g的内存空间,这种情况下,溢出是在所难免的!
解决步骤
调整jvm虚拟机内存
- 进入你的jdk路径下的/jre/lib/amd64目录
- 修改jvm.cfg
- 服务器本身内存充足,除了对外提供服务,其他部分占用内存都不大,所以进行了如下配置
- 配置不可能一簇而就,需要多次调整,如果服务器本身性能不行,就要考虑从限流方面入手!
调整tomcat的内存(单机请忽略)
windows打开tomcat文件夹bin目录下的CATALINA.bat文件
linux打开tomcat文件夹bin目录下的CATALINA.sh文件
在所有配置之前 添加如下配置
CATALINA_OPTS="-Xms21g -Xmx21g -Xmn4g -XX:MaxDirectMemorySize=1g -XX:+UseParallelGC $CATALINA_OPTS $LOGGING_CONFIG $JAVA_OPTS"
注意:我们是双tomcat服务器,并且负载均衡策略权重相同,所以是平分了jvm配置,请你根据实际需求进行调整!