最近一个运行了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. 浅入深出Vue:注册

    基本布局已经有了, 现在我们来开始做我们的注册页面~ 当然需要注册才能发表文章啊(糟老头子坏得很, 我可以只有我一个人能发啊). 这里我们设定只有注册才能发表文章,也就淡化了管理员这个概念.在开发中先 ...

  2. 使jira支持reopen率的统计

    jira本身并不能统计bug的reopen率,虽然bug工作流程中有reopen节点,只能借助第三方插件来处理. 插件名称:Enhancer Plugin for JIRA,此插件支持自定义字段.自定 ...

  3. python实现DFA模拟程序(附java实现代码)

    DFA(确定的有穷自动机) 一个确定的有穷自动机M是一个五元组: M=(K,∑,f,S,Z) K是一个有穷集,它的每个元素称为一个状态. ∑是一个有穷字母表,它的每一个元素称为一个输入符号,所以也陈∑ ...

  4. 编译AMQP-CPP

    1 cd  ./AMQP-CPP/examples/boost$ 2.cmake . 提示boost版本太低, 首先要编译生成boost安装工具bjam进入boost目录执行:./bootstrap. ...

  5. Dubbo服务注册与发现

    目录 一.分布式基本理论 1.1.分布式基本定义 1.2 架构发展演变 1.3.RPC简介 二.Dubbo理论简介 三.Dubbo环境搭建 3.1 Zookeeper搭建 3.2 Dubbo管理页面搭 ...

  6. 【原】深度学习的一些经验总结和建议 | To do v.s Not To Do

    前言:本文同步发布于公众号:Charlotte数据挖掘,欢迎关注,获得最新干货- 昨天看到几篇不同的文章写关于机器学习的to do & not to do,有些观点赞同,有些不赞同,是现在算法 ...

  7. Windows系统配置java环境

    1:下载jdk  网址:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 2:下载 ...

  8. [Abp vNext 源码分析] - 6. DDD 的应用层支持 (应用服务)

    一.简要介绍 ABP vNext 针对于应用服务层,为我们单独设计了一个模块进行实现,即 Volo.Abp.Ddd.Application 模块. PS:最近博主也是在恶补 DDD 相关的知识,这里推 ...

  9. JAVA面试题 String s = new String("xyz");产生了几个对象?

    面试官Q1:请问String s = new String("xyz");产生了几个对象? 对于这个Java面试题,老套路先上代码: public class StringTest ...

  10. 如何使用 nvm-windows 管理 nodejs 版本

    写在前边的话: (1). 路径一定不要包含空格,如 Program Files 这样,所以有把程序安装到 D:\Program Files 文件下的同学请注意了:(2). 为了避免 nvm 无法切换源 ...