上一篇介绍了一些简单的java命令,这次难度稍微加深一点点,介绍几个高级一点的java命令jinfo和jstack。
jinfo也许当你运行jinfo命令时,可能会遇到java.lang.InternalError:Metadata does not appear to be polymorphic的异常,如下图:
解决方式就是安装相应的jdk debug包。因为我的环境是Ubuntu和openjdk1.8的环境,所以执行以下命令,安装openjdk-8-dbg包
sudo apt-get install openjdk-8-dbg
–flags查看jvm参数
执行jinfo -flags命令可以查看java进程的相关参数,包括jvm默认缺省的参数也显示出来了,这个是jps -lv是查看不到的。
jinfo -flags pid
-sysprops查看系统参数
执行jinfo -sysprops 命令可以查看系统相关参数
jinfo -sysprops 312
动态修改jvm参数
先查看那些jvm参数可以修改
java -XX:PrintFlagsFinal -version | grep manageable
能调整的jvm参数并不多,比较实用就PrintGC,下面试试吧
jinfo -flag PrintGC=1 312
运行后可以看到参数确实被修改了
jstack命令是非常实用的一个命令,可以查看死锁和一些线程特别高的问题。
死锁先写一个死锁的java程序
public class DeadThread {
static final Object lockOne = new Object();
static final Object lockTwo = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(new ThreadOne());
Thread thread2 = new Thread(new ThreadTwo());
thread1.start();
thread2.start();
}
static class ThreadOne implements Runnable {
@Override
public void run() {
try {
synchronized (lockOne) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
synchronized (lockTwo) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
}
}
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class ThreadTwo implements Runnable {
@Override
public void run() {
try {
synchronized (lockTwo) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
synchronized (lockOne) {
System.out.println(Thread.currentThread().getName());
Thread.sleep(3000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
然后编译java文件,并运行起来
javac DeadThread.java
java DeadThread
使用jstack输出线程运行日志,可以方便技术人员去查找有不有死锁
jstack -l pid > jstack.log
打开jstack.log日志文件,部分日志如下
输出的文件最下方有死锁的提示Found 1 deadlock,具体死锁的线程就是刚才那个java代码中,ThreadOne和ThreadTwo相互锁了对方的对象,造成了死锁。日志文件也可以看得出来locked和waiting。Thread-0锁了0x000000077db71098,等待0x000000077db710a8,而另一个Thread-1正好相反,所以造成了死锁。
这里需要注意的是,开发人员在写代码的时候,建议给自己的线程起一个名字,方便后期出问题时可以快速定位。一个真实的项目里面,线程是很多的,有些问题很难排查,有了线程名字就减少了一定的工作量。
有些公司可以上生产环境的排查问题,有时发现CPU很高时
测试用的java代码如下
public class HighCPU {
static final Object lockOne = new Object();
static final Object lockTwo = new Object();
public static void main(String[] args) {
new Thread(() -> {
while (true){
int num = 100;
for (int i = 0; i < 1000; i++) {
num /= 10;
num *= 10;
}
}
}).start();
}
}
使用top -Hp pid,查看线程。可以查看具体是哪个线程出现问题,如下图
top -Hp 646
很显然有一个名称为Thread-0的线程CPU很高,于是我们也可以使用jstack看一下线程日志。
这里的pid指的是线程id,pid666的线程需要转成16进制,因为jstack日志里面的id是16进制的。可以使用printf命令转换为16进制,也用一些百度里或者手机里的工具,很简单。
printf "%x\n" 666
线程id666转换成16进制就是29a。在jstack日志文件搜索0x29a,可以找到一个nid=0x29a的线程,这样排查就可以定位大概是那一行代码的问题了。从下图,可以发现是HighCPU这个类的第9行正在运行,问题估计就在那里了。
回到代码,来到第9行,可以发现这里有一个死循环在不停的运行。
这一篇介绍两个高级一点的java命令,也是排查程序很实用的命令。当然很多大公司是不能上生产环境服务器的,也就不可能在生产环境使用上面的命令。不过测试环境还是可以开放给开发人员上去调试的。那如果生产环境不能上,又出现了测试环境无法重现的问题怎么办呢?我们还有dump文件,时候不早了,下一篇再介绍吧。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)