系统堆栈、内存、线程异常预防及排查
异常预防及排查
异常预防及排查
以下命令请勿轻易在生产环境尝试,如需日常调试需屏蔽负载
异常预防
预防为主,排查为辅,提前给服务器配置合理的JVM参数,加强系统监控及管控,减少问题
- 1)堆(Heap)和非堆(Non-heap)内存
按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。
可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,
所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法的代码都在非堆内存中。
- 堆内存分配
JVM初始分配的堆内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的堆内存由-Xmx指定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;
空余堆内存大于70%时,JVM会减少堆直到-Xms的最小限制。因此服务器一般设置-Xms、-Xmx 相等以避免在每次GC 后调整堆的大小。
说明:如果-Xmx 不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM,不是Throwable的,无法用try…catch捕捉。
-
非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。(还有一说:MaxPermSize缺省值和-server -client选项相关,
-server选项下默认MaxPermSize为64m,-client选项下默认MaxPermSize为32m。这个我没有实验。)
上面错误信息中的PermGen space的全称是Permanent Generation space,是指内存的永久保存区域。还没有弄明白PermGen space是属于非堆内存,还是就是非堆内存,但至少是属于了。
XX:MaxPermSize设置过小会导致java.lang.OutOfMemoryError: PermGen space 就是内存益出。
说说为什么会内存益出:
(1)这一部分内存用于存放Class和Meta的信息,Class在被 Load的时候被放入PermGen space区域,它和存放Instance的Heap区域不同。
(2)GC(Garbage Collection)不会在主程序运行期对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS 的话,就很可能出现PermGen space错误。
这种错误常见在web服务器对JSP进行pre compile的时候。 -
参数详解
参数字典:https://www.cnblogs.com/cheng21553516/p/11221114.html
推荐加的参数有:-server:该参数提供服务模式启动-XX:+PrintGCDetails:该参数禁止程序主动FullGC,防止代码调用导致的FullGC
TRP服务器参数推荐(系统虚拟机32C64G)
-Dfile.encoding=UTF-8 -server -Xms32768m -Xmx32768m -Xmn16384m -XX:MetaspaceSize=16384M -XX:SurvivorRatio=10 -XX:MaxTenuringThreshold=15 -XX:NewRatio=2 -XX:+DisableExplicitGC -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xlo
ggc:/data/apache-tomcat-8.0.47/logs/gc.$$.log
系统排查
-
查看系统当前简况
jcmd 查看当前服务器有哪些java程序![]()
jstat -gc pid 当前程序GC情况![]()
以下两个参数,可以反映出当前系统是否存在过多的FullGC,可多次运行对比:FGC:FullGC次数FGCT:FullGC总停止时间
-
保存现场,回复系统
根据刚才的PID,可以使用jmap -heap pid 进行简单的堆内存查看![]()
当判断系统内存使用率过高,且不下降时,简单的排查无法定位问题,则必须保留线程,导出dump文件,然后恢复系统(如重启),导出的命令如下jmap -dump:format=b,file=2020.**.hprof -F pidps:如果系统内存已满,命令无法执行,需要加 -F,注:该命令对系统的内存消耗较大,执行时需要时刻监控应用状态
导出的文件下载到本地pc,进行分析,分析工具推荐eclipse MAT
免安装版本eclipse MAT,下载地址:http://www.eclipse.org/mat/downloads.php
PS:由于对PC配置要求较高,需下载64位

修改配置文件
改成符合文件大小的内存

打开mat,导入前面导出的dump文件,使用Dominator Tree和Leak Suspects进行分析
Leak Suspects会直接排可能有问题的点

总结:很多内存问题,都是由于对内存的预估不足,导致内存溢出,其实内存泄漏的情况比较少,内存溢出一般在遵循开发规范后大部分可以避免的。
线程问题
- 简单查看线程情况
top -H -p pid \找出java进程中cup使用率较高的线程

printf ‘%x\n’ pid 由于线程地址为16进制,故需转换成16进制
然后可以找到CPU占用率最高线程的执行详情
jstack PID|grep nid -A 30 \找到对应线程id的堆栈信息
当前GC线程最活跃
-
线程信息分析
打印当前所有线程信息
jstack -l 16808 >jstack.log
打印完成后,查看当前系统线程各个状态数量
cat jstack.log | grep “java.lang.Thread.State” | sort -nr | uniq -c![]()
主要查看当前系统是否存在Block状态线程 -
分析线程导出信息文件
使用vim编辑器打开前面导出的线程信息![]()
搜索对应的代码开头,统计相对的相同的线程数量,隔断时间多次对比,如果线程长时间存在处于待运行RUNNABLE状态,则需要排查该段代码





浙公网安备 33010602011771号