Tomcat window环境下出现java.lang.OutOfMemoryError: Java heap space的奇怪解决方案

【开发者须知】

     可能在搜索“java.lang.OutOfMemoryError: Java heap space”这个问题的时候,已经搜出了大量雷同的答案,说在catalina.sh配置中加JAVA_OPTS参数等等,如果能解决您的问题,那么恭喜,如果仍未解决,请参考我的文章。我是花了2天的时间才找到解决方案。

    本文只在我所在的Windows+Tomcat+Java11环境中处理,其他环境未必有参考价值。

【故障现象】

     Tomcat是8.5版,运行环境是Windows,Tomcat是以Windows服务形式启动和关闭。

     原本在Eclipse开发环境中,使用Java读取MySQL数据,很正常,后来将class放到生产环境中,发现读大量数据时,Tomcat的HTTP链接直接终止,程序的try-catch并没有捕捉到错误。

    于是在Tomcat的tomcat8-stderr.xxxxx.log中发现这样一段日志:

......上面太多了,各种Error

java.lang.OutOfMemoryError: Java heap space

【排查过程】

    1、这个错误是什么意思?

        用“java.lang.OutOfMemoryError: Java heap space”做关键字查资料,意思就是Java虚拟机JVM的堆内存不够,溢出了。

    2、那我的堆内存现在是多少?

        由于我对Java并不是很深入研究,所以并不了解配置,当听说“堆内存”不够时,也是懵了,一头雾水的样子,这玩意儿不应该是系统自己本身就识别硬件并且在硬件基础上自动分配吗?查了一堆答案也是说自动分配“1/4物理内存”,而生产的机器内存是32G,理论上应该有8G,怎么不够呢?

        那就查查吧:

        在生产环境Java的代码(根据实际应用,找个管理员功能模块)中加入以下代码:

......
System.out.println("最大可用内存,对应-Xmx:"+Runtime.getRuntime().maxMemory());
//System.out.println("当前JVM空闲内存:"+Runtime.getRuntime().freeMemory());
//System.out.println("当前JVM占用的内存总数:"+Runtime.getRuntime().totalMemory());
......

        运行后输出结果为:

最大可用内存,对应-Xmx:268435456

        非常奇怪,看上去才256M,难怪会溢出。

    3、搜索现成答案(没解决)

发现大量文章都说在

catalina.bat的第一行增加:

set JAVA_OPTS=-Xms800m -Xmx800m -XX:PermSize=128M -XX:MaxNewSize=256m -XX:MaxPermSize=256m 

或修改TOMCAT_HOME/bin/catalina.sh
在“echo "Using CATALINA_BASE:   $CATALINA_BASE"”上面加入以下行:
JAVA_OPTS="-server -Xms800m -Xmx800m   -XX:MaxNewSize=256m"

        上面的方案并未解决我这个问题,无论怎么修改,Tomcat重启后仍然是识别256M的最大内存。

【意外转机】

        经过1天半的各种修改,已经找不到办法了,最后随手打开catalina.xxxxxx.log文件,意外发现文件内有几行日志:

28-Dec-2022 13:15:22.133 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Xms128m
28-Dec-2022 13:15:22.133 信息 [main] org.apache.catalina.startup.VersionLoggerListener.log 命令行参数:       -Xmx256m

     咦?这里的256M哪里来的?会不会就是这货的值最直接生效?

     于是再找答案,其实也没找到,于是想想翻一下“bin/service.bat”文件,意外意外地发现有这么三行:

if "%SERVICE_STARTUP_MODE%" == "" set SERVICE_STARTUP_MODE=manual   
if "%JvmMs%" == "" set JvmMs=128
if "%JvmMx%" == "" set JvmMx=256

        这时,才领悟到原来在服务的代码里面设置了这个JVM的最大内存值为256M。


↓答案及步骤就在这↓

        找到问题好办了,就直接修改这里的数据,其中8192是8G:

if "%SERVICE_STARTUP_MODE%" == "" set SERVICE_STARTUP_MODE=manual   
if "%JvmMs%" == "" set JvmMs=8192
if "%JvmMx%" == "" set JvmMx=8192

        然后卸载一次Tomcat的windows服务:

D:\apache-tomcat-8.5.73\bin>service remove

        再重新安装一遍windows服务:

D:\apache-tomcat-8.5.73\bin>service install

        这时再回头看catalina.xxxxxx.log已经是8192了,Runtime.getRuntime().maxMemory()也返回8589934592的值了。再去执行生产代码,发现正常了。问题就这样解决了。


【总结】

        很深入的原因我不打算知道,通过分析,大概估计Tomcat的Windows版本作为服务启动时,可能不加载catalina.sh或catalina.bat文件,所以网上流传的解决方案不能生效。

        最后修改bin/service.bat里面的JvmMx和JvmMs解决问题。

  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值