最近一个运行了4年的javaee web项目,经常接到客户反馈系统无法打开。登录服务器查看服务,发现是tomcat自动关闭了。基本是3到4天发生一次。

运维人员开始以为是其他服务杀死了tomcat服务,没放在心上,解决方法就是直接重启tomcat。

最终捅了篓子,运维人员被客户投诉,扣了一个月的绩效。

解决这个bug兜兜转转来到了我这里。既然接到任务,那就开干,没有解决不了的bug。

系统的运行环境如下:

tomcat6.0

32位jdk7.0

window server2003 32位,32G内存。

查看日志,如果tomcat闪崩,都会在tomcat的bin目录下生成以"hs_err"开头的日志文件。打开最新的日志文件,首先看到的是下面一段话:

# There is insufficient memory for the Java Runtime Environment to continue.
# Native memory allocation (malloc) failed to allocate 32756 bytes for ChunkPool::allocate
# Possible reasons:
# The system is out of physical RAM or swap space
# In 32 bit mode, the process size limit was hit
# Possible solutions:
# Reduce memory load on the system
# Increase physical memory or swap space
# Check if swap backing store is full
# Use 64 bit Java on a 64 bit OS
# Decrease Java heap size (-Xmx/-Xms)
# Decrease number of Java threads
# Decrease Java thread stack sizes (-Xss)
# Set larger code cache with -XX:ReservedCodeCacheSize=
# This output file may be truncated or incomplete.
#
# Out of Memory Error (allocation.cpp:211), pid=7864, tid=6556
#
# JRE version: Java(TM) SE Runtime Environment (7.0_79-b15) (build 1.7.0_79-b15)
# Java VM: Java HotSpot(TM) Server VM (24.79-b02 mixed mode windows-x86 )
# Failed to write core dump.

大概意思就是内存不够了,无法分配32756字节的空间。同时给出几个解决方法:

1、减少系统内存负载;

2、增加物理内存或者交换空间;

3、在64位操作系统上使用64位jdk;

4、减少java heap大小;

5、减少java线程数量;

6、减少java线程堆栈大小。

通过上面的内容可以得出,jvm无法分配32756 bytes的内存空间。

从接到任务开始,我一直以为是jvm配置出错,导致内存不够用,只需调整下新生代、老年代的配置即可。

继续往下看日志文件,找到"GC Heap History (10 events):"这一行,这个记录jvm最后10次垃圾回收时堆的变化情况。

GC Heap History (10 events):
Event: 572312.299 GC heap before
{Heap before GC invocations=5046 (full 357):
PSYoungGen total 201472K, used 200685K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 100% used [0x573c0000,0x63540000,0x63540000)
from space 3328K, 76% used [0x63540000,0x637bb528,0x63880000)
to space 3328K, 0% used [0x63880000,0x63880000,0x63bc0000)
ParOldGen total 843776K, used 422602K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d872b18,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
Event: 572312.305 GC heap after
Heap after GC invocations=5046 (full 357):
PSYoungGen total 201472K, used 1103K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 0% used [0x573c0000,0x573c0000,0x63540000)
from space 3328K, 33% used [0x63880000,0x63993c90,0x63bc0000)
to space 3328K, 0% used [0x63540000,0x63540000,0x63880000)
ParOldGen total 843776K, used 423618K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d970b18,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
}
Event: 572351.132 GC heap before
{Heap before GC invocations=5047 (full 357):
PSYoungGen total 201472K, used 199247K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 100% used [0x573c0000,0x63540000,0x63540000)
from space 3328K, 33% used [0x63880000,0x63993c90,0x63bc0000)
to space 3328K, 0% used [0x63540000,0x63540000,0x63880000)
ParOldGen total 843776K, used 423618K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d970b18,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
Event: 572351.137 GC heap after
Heap after GC invocations=5047 (full 357):
PSYoungGen total 201472K, used 1615K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 0% used [0x573c0000,0x573c0000,0x63540000)
from space 3328K, 48% used [0x63540000,0x636d3ec8,0x63880000)
to space 3328K, 0% used [0x63880000,0x63880000,0x63bc0000)
ParOldGen total 843776K, used 423674K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d97eb18,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
}
Event: 572398.649 GC heap before
{Heap before GC invocations=5048 (full 357):
PSYoungGen total 201472K, used 199759K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 100% used [0x573c0000,0x63540000,0x63540000)
from space 3328K, 48% used [0x63540000,0x636d3ec8,0x63880000)
to space 3328K, 0% used [0x63880000,0x63880000,0x63bc0000)
ParOldGen total 843776K, used 423674K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d97eb18,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
Event: 572398.655 GC heap after
Heap after GC invocations=5048 (full 357):
PSYoungGen total 201472K, used 1998K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 0% used [0x573c0000,0x573c0000,0x63540000)
from space 3328K, 60% used [0x63880000,0x63a73830,0x63bc0000)
to space 3328K, 0% used [0x63540000,0x63540000,0x63880000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51848K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62138,0x13bc0000)
}
Event: 576881.689 GC heap before
{Heap before GC invocations=5049 (full 357):
PSYoungGen total 201472K, used 200142K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 100% used [0x573c0000,0x63540000,0x63540000)
from space 3328K, 60% used [0x63880000,0x63a73830,0x63bc0000)
to space 3328K, 0% used [0x63540000,0x63540000,0x63880000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51850K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62850,0x13bc0000)
Event: 576881.696 GC heap after
Heap after GC invocations=5049 (full 357):
PSYoungGen total 201472K, used 3155K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 0% used [0x573c0000,0x573c0000,0x63540000)
from space 3328K, 94% used [0x63540000,0x63854cb0,0x63880000)
to space 3328K, 0% used [0x63880000,0x63880000,0x63bc0000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51850K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e62850,0x13bc0000)
}
Event: 580535.452 GC heap before
{Heap before GC invocations=5050 (full 357):
PSYoungGen total 201472K, used 201299K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 198144K, 100% used [0x573c0000,0x63540000,0x63540000)
from space 3328K, 94% used [0x63540000,0x63854cb0,0x63880000)
to space 3328K, 0% used [0x63880000,0x63880000,0x63bc0000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e64228,0x13bc0000)
Event: 580535.459 GC heap after
Heap after GC invocations=5050 (full 357):
PSYoungGen total 200960K, used 1858K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 197632K, 0% used [0x573c0000,0x573c0000,0x634c0000)
from space 3328K, 55% used [0x63880000,0x63a50be0,0x63bc0000)
to space 3584K, 0% used [0x634c0000,0x634c0000,0x63840000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e64228,0x13bc0000)
}

看了上面的内容,并没有发现tomcat闪崩是由于老年代,持久代,新生代空间不足引起的。有好几次因为eden区空间使用到100%引起的full gc,但是垃圾回收过后eden区的空间都恢复到正常的水平。

日志中还记录了tomcat闪崩时heap堆的使用情况:

Heap
PSYoungGen total 200960K, used 95671K [0x573c0000, 0x63bc0000, 0x63bc0000)
eden space 197632K, 47% used [0x573c0000,0x5cf5d230,0x634c0000)
from space 3328K, 55% used [0x63880000,0x63a50be0,0x63bc0000)
to space 3584K, 0% used [0x634c0000,0x634c0000,0x63840000)
ParOldGen total 843776K, used 423703K [0x23bc0000, 0x573c0000, 0x573c0000)
object space 843776K, 50% used [0x23bc0000,0x3d985cc0,0x573c0000)
PSPermGen total 262144K, used 51856K [0x03bc0000, 0x13bc0000, 0x23bc0000)
object space 262144K, 19% used [0x03bc0000,0x06e64228,0x13bc0000)

一切都那么正常,同时又那么诡异。

翻看了之前发生日志,内容都是大同小异。

重新翻看了几遍日志,这次把重点放在日志中建议的解决方案上:

#   Reduce memory load on the system
# Increase physical memory or swap space
# Check if swap backing store is full
# Use 64 bit Java on a 64 bit OS
# Decrease Java heap size (-Xmx/-Xms)
# Decrease number of Java threads
# Decrease Java thread stack sizes (-Xss)

其中下面几个解决方案不采用:

  • Reduce memory load on the system。 系统内存够用,32G的内存,还剩20G没用,无需减少内存。
  • Increase physical memory or swap space。 系统内存够用,32G的内存,还剩20G没用,无需增加物理内存。
  • Use 64 bit Java on a 64 bit OS。 32位操作系统,无法使用64位jdk。

只剩下下面的三个解决方案了:

  • Decrease Java heap size (-Xmx/-Xms)。 heap堆设置过大,就会影响剩余内存。
  • Decrease number of Java threads
  • Decrease Java thread stack sizes (-Xss)

而减少java线程的数量,需要修改代码,这个也不实际。

最后只剩下

  • Decrease Java heap size (-Xmx/-Xms)
  • Decrease Java thread stack sizes (-Xss)

这两个解决方案了,就从这里入手,曙光就在前方。

先看 Decrease Java thread stack sizes (-Xss) 解决方案

java线程运行也是需要内存空间的,-Xss参数指定每个线程堆栈的大小,为jvm启动的每个线程分配的内存大小。在jdk1.4版本中是256K,JDK1.5及以上版本是1M。

tomcat jvm的参数设置如下:

JAVA_OPTS=%JAVA_OPTS% -server -Xms1024m -Xmx1024m -Xmn200M -XX:PermSize=256M -XX:MaxPermSize=512m -XX:SurvivorRatio=1 -Xss256k

已经通过-Xss设置每个java线程堆栈的大小为256K。

在java语言里, 当你创建一个线程的时候,虚拟机会在JVM内存创建一个Thread对象同时创建一个操作系统线程,而这个系统线程的内存用的不是JVMMemory,而是系统中剩下的内存(MaxProcessMemory - JVMMemory - ReservedOsMemory)。

当需要创建线程,而操作系统剩余内存不够分配给一个java线程时,就会报Out of Memory Error的错误。

由于已经设置通过-Xss设置java线程栈的大小为256K,因此也决定不采用这个解决方案。

现在只剩 下Decrease Java heap size (-Xmx/-Xms) 这个解决方案了。通过减少堆的大小,而留出足够的内存空间给java线程堆栈使用。

32位的window操作系统给每个进程分配的内存空间是2G,减去堆的最大容量和PermSize的最大容量,剩下的容量就留给java线程栈使用。

经过分析代码和之前错误的日志,发现一般在350个线程这样就出现Out of Memory Error的错误。

在出现错误时,heap空间才用了不到40%。因此决定将java heap的从1G减少到768M。

修改的jvm参数如下:

JAVA_OPTS=%JAVA_OPTS% -server -Xms768m -Xmx768m -Xmn200M -XX:PermSize=256M -XX:MaxPermSize=512m -XX:SurvivorRatio=1 -Xss256k

到目前为止,系统已经稳定运行1个月,各个参数指标都在正常范围内。heap使用率最高才70%。

总结:

1、经过这次解决bug,加深了对java虚拟机的了解,特别是线程栈,内存堆,持久代,新生代等概念。

2、一定要仔细阅读日志文件,一步一步排除掉潜在的解决方案。综合系统的运行环境,找出合理的解决方案。

记一次解决tomcat自动关闭的bug的更多相关文章

  1. 记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法

    原文:记CRenderTarget:DrawText()绘制中文乱码的BUG及解决办法 转载请注明出处:http://www.cnblogs.com/Ray1024 一.问题描述 在MFC中使用Dir ...

  2. Eclipse提示Tomcat miss丢失bug:The Tomcat server configuration at \Servers\Tomcat v5.5 Server at localhost-config is missing.

    Eclipse提示Tomcat miss丢失bug:The Tomcat server configuration at \Servers\Tomcat v5.5 Server at localhos ...

  3. tomcat自动关闭了。

    测试方法: 1.狂点抽取大量数据的接口 结果: jvm里面的现成崩溃.导致tomcat错误. 思路: 最近发现tomcat老是自动关闭,开始也发现了,不过没放在心上,直到今天,请求一提交到服务器,to ...

  4. 怎么解决tomcat占用8080端口问题

        怎么解决tomcat占用8080端口问题 相信很多朋友都遇到过这样的问题吧,tomcat死机了,重启eclipse之后,发现 Several ports (8080, 8009) requir ...

  5. 解决tomcat部署多个虚拟机时报IllegalStateException: Web app root system property already set to 的问题

    解决tomcat部署多个虚拟机时报IllegalStateException: Web app root system property already set to 的问题 在web.xml中添加如 ...

  6. 怎么解决tomcat占用8080端口问题图文教程(转)

    亲测有效. 原因:可能是开了多个tomcat 原文网址:http://jingyan.baidu.com/article/1612d5006c3cdae20e1eee04.html  怎么解决tomc ...

  7. 解决tomcat占用8080端口

    怎么解决tomcat占用8080端口问题图文教程           怎么解决tomcat占用8080端口问题 相信很多朋友都遇到过这样的问题吧,tomcat死机了,重启eclipse之后,发现 Se ...

  8. 记一次解决cmd中执行java提示"找不到或无法加载主类"的问题

    今天遇到一个问题:在cmd命令行中,用javac编译java文件可以成功,但是用java执行却提示“找不到或无法加载主类”.现将该问题的原因以及解决办法记录一下. 先理解一下系统变量path和clas ...

  9. 转:解决tomcat服务器跨域问题

    原文地址: 解决tomcat服务器跨域请求问题 注:还未测试 在tomcat 的web.xml 配置文件中加入如下配置过滤器 (如web.xml中有多个filter时要把下面配置放在最前端) < ...

随机推荐

  1. div+css 布局技巧总计

    一.css 样式 1.float 首先需要了解块级元素(block element).每个块级元素都默认占用一行,在同一行只能添加一个块元素(float 除外).块级元素一般可以嵌套块级元素或者行内元 ...

  2. C语言学习推荐《C语言参考手册(原书第5版)》下载

  3. MySql突然连接不上,报Can't connect to MySQL server on 'localhost' (10061),并且没有mysqld时解决方案

    今天连接数据库时突然连接不上,前一天还是好好的.打开数据库就报 Can't connect to MySQL server on 'localhost' (10061) 一直也知道是MySQL服务没有 ...

  4. java网络爬虫,乱码问题终于完美解决

    第一次写爬虫,被乱码问题困扰两天,试了很多方法都不可以,今天随便一试,居然好了. 在获取网页时创建了一个缓冲字节输入流,问题就在这个流上,添加标红代码即可 BufferedReader in = nu ...

  5. (转)代码结构中Dao,Service,Controller,Util,Model是什么意思?

    作者:技能树IT修真院链接:https://www.zhihu.com/question/58410621/answer/623496434来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  6. [记录]python使用serial模块实现实时WebConsole

    ###tornado+websocket+多进程实现: 1.index.html <!DOCTYPE HTML> <html> <head> <style&g ...

  7. 使用ML-Agents Toolkit(0.5)训练游戏ai之游戏打包

    这篇文章介绍如何训练官方的一个例子3dball. 确保在此之前已经安装好训练环境可以参考下面的文章. https://www.cnblogs.com/pojdd/p/9804322.html 游戏打包 ...

  8. 【机器学习理论】换底公式--以e,2,10为底的对数关系转化

    我们在推导机器学习公式时,常常会用到各种各样的对数,但是奇怪的是--我们往往会忽略对数的底数是谁,不管是2,e,10等. 原因在于,lnx,log2x,log10x,之间是存在常数倍关系. 回顾学过的 ...

  9. 个人永久性免费-Excel催化剂功能第40波-工资、年终奖个人所得税计算函数

    学Excel的表哥表姐们必定有接触过个人所得税的案例学习,在计算个人所得税这个需求上,大家的层次也是很多种多样,当然Excel催化剂推荐的方式仍然是经过封装后的简单明了的自定义函数的方式,此篇已为财务 ...

  10. 自定义View之开关

    资源文件 首先我们需要有两个图片文件,分别是开关的背景和开关的滑块 自定义View 1.写一个类继承View 2.copy该类的全路径名在布局文件使用, 3.找到这个控件,设置初始信息 4.根据需求绘 ...