????????在研发的过程中,我们肯定都遇到过各种各样的应用问题,下面总结一些常见问题及相关解法,包括但不限于CPU飙升、线程死锁、内存泄露、垃圾回收问题、类加载问题、网络问题、日志问题和安全性问题,后续会持续补充完善
- 响应时间延长:CPU使用率过高会导致进程无法及时处理请求,从而导致Web应用的响应时间延长,影响用户体验。
- 性能下降:高CPU使用率会消耗系统资源,导致其他进程或服务的性能下降,可能引起整体系统的不稳定性。
- 可用性降低:CPU使用率过高持续一段时间,可能导致Web应用崩溃或无法正常运行,从而降低系统可用性。
大量并发请求:大量并发请求时,可能会导致CPU使用率升高,特别是在处理复杂的请求或计算密集型任务时。
资源泄露:内存泄露、数据库连接未释放或文件句柄未关闭等资源泄露问题可能导致CPU使用率持续增长。
- 代码问题:低效的算法、非优化的数据库查询、死循环、频繁的IO操作等代码问题可能导致CPU使用率升高。
使用 top 命令定位最耗 CPU 的进程
找到该进程下最耗费cpu的线程?? top -Hp pid
此时得到的线程ID(pid)为10进制数据,方便匹配stack中的信息,转为 16 进制,俩种转换方式
a、手动转换进制 printf?“%x\n” 2608??? //?转换16进制(转换后为0xa30)
b、在线工具转换? >>??在线进制转换
使用 16 进制的线程ID(xa30)匹配堆栈信息,jstack pid |grep 'threadId'??-C5 --color?
根据该线程的堆栈信息结合实际代码分析CPU飙升的具体原因
死锁:指两个或多个线程互相等待对方释放资源而无法继续执行的情况
- 应用停滞或崩溃:当线程死锁发生时,涉及的线程将无法继续执行,导致应用停滞或崩溃。这会影响应用的可用性和用户体验。
- 资源浪费:死锁会导致线程无法释放已经占用的资源,从而导致资源的浪费。这可能会降低应用的性能,并占用系统的资源。
- 竞争资源:多个线程同时竞争有限的资源,当资源分配和释放不当时,可能会导致死锁
- 循环等待:线程之间相互等待对方释放资源,形成循环等待的局面
查看 java 进程的线程快照信息并过滤死锁信息?jstack -l 2598 | grep deadlock,线程死锁的程序,会导致某些操作处于waiting中
指的是在程序中动态分配的内存空间在不再使用时无法被回收,导致这部分内存无法再被其他程序使用。这种情况下,应用程序所占用的内存会不断增加,最终可能导致系统的内存耗尽,导致系统服务OOM(OutOfMemoryError)异常或崩溃
内存泄漏的原因通常是由于程序中存在对内存的引用,导致垃圾回收器无法回收这些被引用的内存。常见的内存泄漏原因,包括但不限于以下几点:
- 对象引用未及时释放:当一个对象不再使用时,如果其引用没有被及时释放,垃圾回收器无法回收该对象,从而导致内存泄漏。如 ThreadLocal 未执行 remove
- 静态集合对象未清理:静态集合对象在整个应用生命周期中保持引用,如果不及时清理其中的对象引用,会导致内存泄漏。
- 资源未正确关闭:当使用一些需要手动关闭的资源(如文件、数据库连接、网络连接等)时,如果在使用完毕后未正确关闭或释放资源,会导致内存泄漏。
- 缓存未正确管理:在缓存中存储的对象如果长时间不被使用,却一直保持在缓存中,会导致内存泄漏。
- 循环引用:当多个对象之间形成循环引用关系时,即使这些对象没有被外部引用,它们也无法被垃圾回收器回收,从而导致内存泄漏。
jmap -heap pid? 首先排查新生代、老生代堆的内存分配情况,是否分配合理或过小?
排查 gc?? fgc ,各分代内存情况,每秒输出一次 gc 分代内存分配情况,以及gc时间
如果 GC 没问题,查看进程占用内存比较大的对象并分析,对于占用空间很大的对象(比如超过了100M),应该着重分析,为何没有释放。
对于堆外内存还需要考虑类的加载情况,jmap -histo:live 2598 | more ?执行后会执行执行一次fgc,生产环境不建议使用,可采用dump内存快照,通过线下工具(jprofilter、MAT等)分析
dump内存快照的命令
jmap -dump:format=b,file=./dump.dat pid: 把Java heap里所有对象都dump下来,无论对象是死是活
?jmap -dump:format=b,live,file=xxx.hprof <pid>:先做一次full GC,然后再dump;垃圾对象会被GC清理掉,不会出现在dump文件中
持续补充完善中......