程序死循环、死锁问题定位

程序死循环、死锁问题定位

在开发过程中,可能由于代码设计问题导致出现了死循环或者死锁的问题,使服务器CPU负载飙高从而导致系统运行缓慢,因此要特别注意防止死循环和死锁的发生。如监控服务器状态时,如果发现CPU负载或利用率飙得很高,这时候就要定位出可能出现的问题,这是在开发中非常重要的能力之一。
主要方法:top 、jstack

定位死循环

  • 模拟一段死循环代码(我这里参考了其他博客的代码来做实验–链接)

  • 打jar包上传到Linux服务端(usr/local/jar)

mvn clean package -Dmaven.test.skip
  • 运行jar包
nohup java -jar monitor_tuning-0.0.1-SNAPSHOT.jar &
  • 访问死循环方法对应的url地址执行死循环代码,top查看运行的jar的进程ID

程序死循环、死锁问题定位_第1张图片
可以看到负载和cpu利用率都飙得很高

  • 问题排查,实验jstack获取对应进程的线程堆栈信息,下载到本地查看
jstack 108196 >108196.txt
rz 108196.txt
  • top -p 108196 -H 查看进程中cpu利用率最高的线程ID记录下来在jstack导出的文件中查看对应信息
    程序死循环、死锁问题定位_第2张图片
  • 使用printf "%x" 108262 转化为16进制然后在jstack导出的文件中查找对应线程ID的信息

程序死循环、死锁问题定位_第3张图片

  • 通过在jstack导出的文件中查看这个线程的方法栈信息可以确定到运行的方法,定位到问题所在,分析代码是否出现了死循环或者是其他原因。

定位死锁

  • 模拟一段死锁代码
/**
	 * 死锁
	 * */
	@RequestMapping("/deadlock")
	public String deadlock(){
		new Thread(()->{
			synchronized(lock1) {
				try {Thread.sleep(1000);}catch(Exception e) {}
				synchronized(lock2) {
					System.out.println("Thread1 over");
				}
			}
		}) .start();
		new Thread(()->{
			synchronized(lock2) {
				try {Thread.sleep(1000);}catch(Exception e) {}
				synchronized(lock1) {
					System.out.println("Thread2 over");
				}
			}
		}) .start();
		return "deadlock";
	}
  • 访问该路径执行这段代码
  • jps查看对应java进程信息
    在这里插入图片描述
  • jstack 109176 > 109176.txt将其导出并sz到本地查看
    程序死循环、死锁问题定位_第4张图片
    可以看到jstack导出的文件记录了死锁,并将发生死锁的两个线程的详细信息记录下来,很清除的就能定位到死锁的位置,很好很强大!

总结:

当发现服务器CPU负载利用率很高时,分析可能出现了死循环或者死锁,通过工具来分析定位问题所在。
死循环:
1、用top查看cpu利用率最高的进程,并用jstack将其进程信息文件导出,
2、用top -p pid -H 查看进程中cpu占用率高的线程,在jstack文件中查询该线程的方法栈信息以定位到问题代码。
死锁:
1、jstack导出进程信息后,查看出现死锁的线程,
2、定位线程中出现死锁的方法,重新设计该段代码排除掉死锁。

补充:导致CPU负载变高的还有其他的原因如频繁的磁盘IO导致进程阻塞,导致CPU利用率飙高的原因也有可能是频繁的GC,具体问题具体解决,都可以使用工具来定位到问题所在。

你可能感兴趣的:(java,项目开发,问题分析,死锁,死循环)