前几天公司采购了华为云的服务器,是基于window server的操作系统,要把与上一个项目所有的服务部署到这一台服务器上,供公司演示和宣传。
首先是要把Tomcat注册为window server的服务,因为你不可能用CMD黑窗口的形式打开,关闭掉窗口同时服务也关掉了,况且其他人用的时候也不方便。要把Tomcat注册成服务形式,要下载基于window版本的Tomcat,从Tomcat的官网上选择对应的版本:
下载之后解压,进入解压后的bin目录里,有一个service.bat的批处理命令,我们就是用这个命令来注册或者移除服务
其中在这个目录下打开cmd窗口,用命令service.bat install 服务名称来注册服务
用命令service.bat remove 服务名称可以移除服务,这是可以在注册表中查看你刚注册的服务:
路径为HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Apache Software Foundation\Procrun 2.0,打开注册表在运行中可以使用命令regedit:
此时我们就可以在任务管理器中找到对应的服务进行启动
项目的启动很正常,证明JVM分配的内存很正常,但是其中一个项目在访问的过程中,服务就挂掉了,查看日志,报了java.lang.OutOfMemoryError:PermGen space的错误,PermGen称为永久保存区域,它不属于Java堆的一部分,是来存放类和类描述的,证明是项目启动过程中加载的类、类描述以及运行过程中动态编译产生的类、类描述超过了设定的大小,导致程序的运行错误,我们可以通过jconsole来查看一下内存区域的分配:
当我们选中内存池“PS Perm Gen”时,发现已经占用的内存就已经快满了,那么在运行过程中产生的类再被加载进去的话,就会出现java.lang.OutOfMemoryError:PermGen space的错误。
首先说明一下,我们是以Tomcat注册服务的形式,所以打开jconsole在本地连接里面是看不到要连接的内存监控:
这时就要用远程连接的方式查看,远程连接需要在注册表中配置相关ip和端口(对应服务---Options),加入:
-Djava.rmi.server.hostname=ip地址
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8089
-Dcom.sun.management.jmxremote.authenticate=false
-Dcom.sun.management.jmxremote.ssl=false
设置好之后重启服务,就可以在远程连接中输入ip:端口来进行内存监控了:
对于java.lang.OutOfMemoryError:PermGen space的错误,我们需要加大这个内存区域的空间大小,如果不是以注册服务的形式启动的Tomcat,也就是用startup.bat启动的,我们就可以在catalina.bat中加入以下设置来调整内存:
set "JAVA_OPTS=-server -Xms256m -Xmx1024m -XX:MaxPermSize=256m"
但是我们是以window服务的形式来启动,所以Tomcat不会读取你在catalina.bat中的相关配置,这时我们还是回到注册表中,在注册表中配置相关参数,让服务启动时读取注册表中的数据,如下:
找到对应的服务,在Options中配置-XX:PermSize=256M -XX:MaxPermSize=512M,大小根据自己项目来调整,重新启动服务,打开jconsole,在项目访问过程中监控PermGen空间区域的大小变化,来确定服务不会因为java.lang.OutOfMemoryError:PermGen space的错误再次挂掉,对症下药,其他的内存区域也可以通过相同的方法来调整大小。
从上图中可以看出,PermGen的内存区域占用率可以达到服务稳定的运行了。
对于jconsole监控的用法以及JVM内存模型,请参考相关专业书籍,在本片博客中就不提及太多了,书籍掌握好了,那么在项目运行过程中出现的问题,也就能对症下药,迎刃而解了。