本文不去介绍JVM性能调优怎么操作,也不讲JDK怎么安装,以及各种安装方式的区别,而是讲解由指令jstack
指令执行出错提示jstack:command not found
的原因及其问题的扩展及其相关的知识。也是自己学习过程中的总结和思考。
如果你也曾遇到过下面的这些问题,有类似的疑惑,那么本文或许会有你有所帮助。
1、以前自己也试过在linux上装jdk,当然了,是参考网上的教程。记得有的文章在第一步是要卸载OpenJDK,没看懂是什么意思,因此又找了其他的文章去安装。
2、想学习JVM性能调优分析,于是参考网上的教程,使用top -Hp pid
指令找出进程中占用cpu过高的线程,然后准备使用jstack -pid
指令进一步分析,结果不像别人博客中写的打印出一堆信息,而是打印出报错信息,提示没有jstack指令:bash: jstack: command not found
,可是百度一查,jstack是jdk自带的指令;
3、执行jstack
指令报错提示说没有该指令,但是执行java -version
却又是正常的,说明不是因为没有配置环境变量的问题。难道真的没有jstack指令吗?于是想要到jdk安装路径下查看是否真的没有jstack指令。参考网上教程的各种方法如打印echo $JAVA_HOME
以及which java
以及whereis java
,结果echo
打印出来的是空,而which java
和whereis java
打印出来的是java指令的执行路径,并非安装路径。那么jdk到底装在了哪里?
4、过段时间再来学习线上程序CPU占用率过高的分析处理,参考了其他的文章,先使用jps
指令查看当前所有java程序的进程号,结果又报错了:-bash: jps: command not found
,于是换一台服务器,竟然执行jps
成功了,jstack指令也成功执行了,可是为什么之前那台服务器却不行呢,到底是什么原因?
5、同事说他负责的某个程序功能很少,可是不知道为什么CPU使用率特别高,于是也是想通过jps
和jstack
等指令去了解原因,可是也是提示command not found
;
很多问题看看似无关,但其实也是有关联的,只要我们找到突破口,或者有人给我们指点一下,我们就会恍然大悟。像上面的几个问题,在了解JDK还分OracleJDK和OpenJDK以及了解他们的区别之后,或许我们就很快能理解并上面的解决了。
先来简单了解下OracleJDK和OpenJDK:
Oracle JDK便是平常我们在windows系统上做开发使用的JDK,又称作SUN JDK。OpenJDK则是大多数linux系统版本自带的JDK。OpenJDK的特点是更新频繁,开源免费,可以自由使用。而Oracle JDK的特点是提供稳定可用的商业版本,商用收费,学习研究免费。
参考文章:https://www.cnblogs.com/vast-yj1234/p/11262767.html
OpenJDK和OracleJDK的区别:
Java由SUN公司(Sun Microsystems, 发起于美国斯坦福大学, SUN是Stanford University Network的缩写)发明,2006年SUN公司将Java开源,此时的JDK即为OpenJDK。
也就是说,OpenJDK是Java SE的开源实现,它由SUN和Java社区提供支持,2009年Oracle收购了Sun公司,自此Java的维护方之一的SUN也变成了Oracle 。
Oracle JDK是基于OpenJDK源代码构建的,因此Oracle JDK和OpenJDK之间没有重大的技术差异。
参考文章:https://www.cnblogs.com/shoufeng/p/9719995.html
简而言之,Java是Sun公司发明,并于2006年将其开源并命名为OpenJDK,在此之前是叫SunJDK,而2009年Oracle公司收购了Sun公司,改名为OracleJDK。自此,就有了OpenJDK和OracleJDK,以及其他基于OpenJDK改进的其他版本如IBM J9, Azul Zulu, Azul Zing。而OracleJDK的开源,是不针对商业使用的,因此如果商业上要使用,则需要付费。但是你可以选择使用OpenJDK,OpenJDK依旧在维护并且其更新频率更高。有的Linux服务器上,会默认装上OpenJDK。
前面说了,有的Linux服务器上,会默认装上OpenJDK。如果没有,则需要我们自己去下载安装。或者当你想要装的是OracleJDK时,就㤇我们自己重新去下载安装JDK。这也就是为什么有的JDK安装教程的博客里面会提到第一步是卸载系统自带的OpenJDK。总之,我们可以根据需要选择下载安装OpenJDK或OracleJDK,相比之下OracleJDK的功能会更全一些,因此我们通常安装OracleJDK,可是商用使用的话OracleJDK是需要付费的,否则则是属于侵权了吧?
当我们下载并安装好JDK后,我们通常使用java -version
来查看jdk是否配置好。我们通常最多只会关注输出信息中的jdk版本是1.7还是1.8还是其他,而不会有更多的注意。现在我们知道JDK是分OracleJDK和OpenJDK之后,我们再来仔细看看java -vesion
的输出信息:
[liweizhi@iZ23vmlb2osZ ~]$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
那在我们之前执行jstack pid
指令时会报错提示bash: jstack: command not found
的服务器上再执行一次java -version
看看:
[liweizhi@iZ2389g2laeZ bin]$ java -version
openjdk version "11.0.4" 2019-07-16 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.4+11-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.4+11-LTS, mixed mode, sharing)
可以看到,一个写的是java(其实也就是OracleJDK)而另一个写的是OpenJDK。通过对其他服务器进行测试,发现所有出现command not found
的服务器都是使用的OpenJDK版本。也就是说,jstack pid
执行不了大概是跟JDK版本有关的,可能是OpenJDK不包含jstack
指令,当然了,也可以能是因为我们所用的OpenJDK没有下载jstack
指令。
于是想要进一步到jdk安装路径下查看是否真的没有jamp、jps、jstack指令,终于通过这篇文章找到了正确寻找Linux下jdk安装路径的方法:https://www.cnblogs.com/756623607-zhang/p/11442320.html。
步骤如下:
1、查看jdk是否安装以及查看java版本——java -version
[liweizhi@iZ23vmlb2osZ bin]$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)
2、查看java命令的执行位置——which java
[liweizhi@iZ23vmlb2osZ ~]$ which java
/usr/bin/java
3、查找java命令的位置所对于的软链地址——ls -l /usr/bin/java
[liweizhi@iZ23vmlb2osZ ~]$ ls -l /usr/bin/java
lrwxrwxrwx 1 root root 22 Aug 15 2018 /usr/bin/java -> /etc/alternatives/java
4、最后通过软链地址查找JDK的安装目录——ls -l /etc/alternatives/java
[liweizhi@iZ23vmlb2osZ ~]$ ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 41 Aug 15 2018 /etc/alternatives/java -> /usr/java/jdk1.8.0_181-amd64/jre/bin/java
jstack、jps
等对于OracleJDK版本的JDK,在其安装路径下的/usr/java/jdk1.8.0_181-amd64/bin
位置下,可以发现确实是有jstack、jmap、jps
等指令的:
[liweizhi@iZ23vmlb2osZ bin]$ pwd
/usr/java/jdk1.8.0_181-amd64/bin
[liweizhi@iZ23vmlb2osZ bin]$ ls
appletviewer jarsigner javah jcmd jhat jmc.ini jstat native2ascii rmid tnameserv
ControlPanel java javap jconsole jinfo jps jstatd orbd rmiregistry unpack200
extcheck javac javapackager jcontrol jjs jrunscript jstatd.all.policy pack200 schemagen wsgen
idlj javadoc java-rmi.cgi jdb jmap jsadebugd jvisualvm policytool serialver wsimport
jar javafxpackager javaws jdeps jmc jstack keytool rmic servertool xjc
而对于装了OpenJDK版本的JDK的安装路径下:
[liweizhi@iZ2389g2laeZ bin]$ pwd
/usr/lib/jvm/java-11-openjdk-11.0.4.11-1.el7_7.x86_64/bin
[liweizhi@iZ2389g2laeZ bin]$ ls
java jjs keytool pack200 rmid rmiregistry unpack200
可以看出,版本是openjdk-11.0.11-1,而且确实是没有jstack、jmap、jps
指令的,甚至连javac
指令都没有。
jstack、jps
等指令实践证明,不是的:
[liweizhi@VM_0_17_centos bin]$ pwd
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/bin
[liweizhi@VM_0_17_centos bin]$ ls
appletviewer idlj javac java-rmi.cgi jdeps jmap jstack native2ascii rmic serialver wsgen
clhsdb jar javadoc jcmd jhat jps jstat orbd rmid servertool wsimport
extcheck jarsigner javah jconsole jinfo jrunscript jstatd pack200 rmiregistry tnameserv xjc
hsdb java javap jdb jjs jsadebugd keytool policytool schemagen unpack200
也许是系统自带的OpenJDK是最精简的,所有不包含jstack
这些指令吧。我们可以使用对JDK进行升级,由于是线上服务,就不敢贸贸然轻举妄动。具体操作可以参考这篇文章:https://blog.csdn.net/qq_32447301/article/details/85109014
至此,上面提到的5个问题就全部解决了。如果遇到没有jstack:command not found
这样的错误信息也不用害怕了,也知道是什么原因导致的了。思路清晰了,问题也就迎刃而解了,就不需要死马当活马医又卸又装,然后自己也不知道怎么回事就把问题给解决了。
然后,就可以继续学习JVM性能调优了,就可以继续深入理解jstack、jmap等指令了。