1.问题现象
- 测试组反馈问题
- 1.系统的后台服务器运行半小时后,CUP飙升,占用内存到10g加,系统操作出现卡顿现象,
- 2.系统重启后问题没有得到改善,仍然是半小时后系统发生之前相同的问题
2.问题分析
通过top –Hp PID查看使用CUP最高的线程的PID
PID 20032使用率最高,是java程序,为了了解系统发生了什么使用jstack输出堆栈信息
通过printf将十进制数 20032转为十六进制数得到4f22,在输出的堆栈信息pid20032.txt中搜索4f22线程工作内容,发现线程一直在做查询操作
分析对应的程序代码发现本应该按照用户id查询的dao处理.缺少了条件拼接造成查询所有用户的信息.因此在内存中创建了大量用户占用信息对象
3.问题原因
合并代码的时候, 查询条件缺失限制条件。 在开发环境中数据量和很小,问题并不明显, 测试环境使用的数据库是省级,数据量为千万级,因此问题十分明显
4.经验教训
1. 输入堆转储文件的时候没有考虑到文件大小
内存占用很大,最先想到的是通过JVM 参数-XX:+HeapDumpOnOutOfMemoryError可以让JVM在出现内存溢出时候Dump出当前的内存转储快照。因此修改JBOSS_HOME/bin/run.conf 文件,修改JVM属性-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/starboss/heapdump(如下)
JAVA_OPTS="-server -Xms8192m -Xmx10240m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+DisableExplicitGC -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/starboss/heapdump"
-XX:+HeapDumpOnOutOfMemoryError参数表示当JVM发生OOM时,自动生成DUMP文件。
-XX:HeapDumpPath=${目录}参数表示生成DUMP文件的路径,也可以指定文件名称,例如:-XX:HeapDumpPath=${目录}/java_heapdump.hprof。如果不指定文件名,默认为:java_<pid>_<date>_<time>_heapDump.hprof‘
因为没有考虑到系统配置的是10g内存, 生成的堆转储文件大小为15g, 这么大的文件使用 Memory Analyzer或者 jmap命令都无法解析文件,直接抛出内存溢出异常 :(
2. jstack命令的时候报错Unable to open socket file
了解这个异常首先要了解jstack命令是如何执行的和 Linux tmp文件夹
Linux tmp文件夹中会保存一些文件
- /tmp文件是linux运行时产生的缓存文件,用于加速二次打开文件的速度。
- /tmp文件在linux关机时会被系统预设指令删除的。
Java程序启动后默认会在 /tmp/hsperfdata_{user_name}的目录下创建一个以PID为文件名的新文件, 并在该文件中存储jvm运行的相关信息, jmap,jstack 等工具会读取 /tmp/hsperfdata_{user_name} 下的 pid 文件获取连接信息
所以出现Unable to open socket file问题可能有两种情况引起
- 当jstack命令用户和java程序启动用户不一致的时候用户就打不开如上的文件 .可以使用命令确认用户名是否一致,
- tmp目录中的文件被删除,这样使用jmap,jstack 命令的时候无法读取PID文件获取连接信息,也会抛出Unable to open socket file。 我遇到的问题就是此问题, 每当内存占用超过8G的时候执行jstack命令都会抛错, 查询时候发现文件已经不存在, 上述的处理都是在内存占用到 5g左右使用jstack命令获取的信息