在做性能测试中不断思考java应用,性能怎么观察,怎么通过方法定位到代码,是否有通用步骤,通过查找资料与查看网上知识、帮助文档之后,才有如下文章,话说知道不等于会,会不等于能运用,只有不断有意识去练习才能掌握。
注意:从操作系统打印出的虚拟机的本地线程看,本地线程数量和Java线程堆栈中的线程数量相同, 说明二者是一一对应的。只不过java线程中的nid中用16进制来表示, 而本地线程中的id用十进制表示。
使用虚拟机演示:
使用top命令查看目前操作系统性能情况:
使用idea编写简单的demo进行演示通过进程到线程定位到代码行:
import com.sdgroup.pojo.StudentInfo;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author liwen
* @Title: PageIndex
* @Description: 使用命令top-->top -p PID -- H jstack pid
* @date 2019/11/9 / 10:23
*/
@Log4j2
@Controller
public class PageIndexController {
/**
* 测试demo
* @return
*/
@GetMapping("/7d")
@ResponseBody
public Object topDemo() {
StudentInfo stInfo = new StudentInfo();
stInfo.setName("topJava");
stInfo.setAge(30);
stInfo.setDes("冠礼之年测试java通过top命令查看jvm");
stInfo.setGrade("7DGroup");
for (int i = 0; i < 100000; i++) {
i++;
try {
log.info("my is print" + i);
Thread.sleep(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return stInfo;
}
/**
* 调试
* @return
*/
@GetMapping("/7ddemo")
@ResponseBody
public Object topDemo1() {
StudentInfo stInfo = new StudentInfo();
stInfo.setName("topJava");
stInfo.setAge(30);
stInfo.setDes("冠礼之年测试java通过top命令查看jvm");
stInfo.setGrade("7DGroup");
return stInfo;
}
}
打开浏览器访问:
访问写好的请求http://ip:port/7d并且通过工具进行访问,通过查看日志显示系统后台运行,前端一直处于等待状态
可以使用jmeter或者idea等工具进行不断访问显示,方便咱们进行性能定位:
也可以使用idea简单发起请求:
点击请求:
打开linux系统,再次打开窗口中敲top命令查看消耗CPU中的java进程,通过观察该进程在操作系统中消耗cpu不是很高,但是为了演示上面操作步骤,咱们暂时使用该进程进行演示:
使用命令top -p PID即可看到该进程下的线程信息
再次使用:jsack 命令进行,打出dump信息
如果执行没有该命令需要找到jdk安装目录执行:
可以参考:https://www.cnblogs.com/lossingdawn/p/10856199.html
[root@localhost bin]#
[root@localhost bin]# ./jstack 93114 >/home/7d/7djava.dump
[root@localhost bin]#
切换到dump生成的目录下:
可以下载到本地进行查看或者使用jdk自带的jvisualvm工具查看:
目前使用文本查看方式
[root@localhost 7d]# vim 7djava.dump
显示信息
发现该进行消耗多,其实也不多,目前是为演示所以暂时使用下。
转换:十进制转换16进制:
在打开dump文件中通过vim搜索命令查找:
从上面可以看出目前线程正处于TIMED_WAITING状态,表示当前被挂起一段时间,时长为参数中指定的时长,如Thread.sleep(1000)。因此该线程当前不消耗CPU。
找到代码的包名与代码行:
从下面信息得出:
再次查看源码:
通过压力工具稳定发压,使用原始命令top查看java进程再通过jstack pid>inof.dump命令打出线程信息,通过top -p pid查看线程,通过判断那个线程消耗cpu,再次通过转换为16进制进程定位到代码。
在实际工作中该方法,经常用于线上定位问题,因为线上机器不能安装其他工具,如果是线下测试其实有很多工具可以使用(Jprofiler、jmc、jvisualvm)等工具。
下面简单介绍下线程怎么看:
"http-nio-8080-exec-11" #30 daemon prio=5 os_prio=0 tid=0x00007fadf8001000 nid=0x16bf8 waiting on condition [0x00007fae6c7d0000]
光知道上面内容咱们做性能测试还是不知怎么下手?其实咱们通过线程分析知道程序他目前处于什么状态,就知道怎么下手分析,你说呢?。
在分析之前需要了解线程生命周期还得知道谁消耗资源。
线程整个生命周期,可以分为五个阶段,分别是新建状态New、就绪状态Runnable、运行状态Running、阻塞状态Blocked和死亡状态Terminated;