VisualVM 线程转储与堆转储不匹配?
VisualVM thread dump not matched with heap dump?
我写了一个死锁的例子代码,然后用VisualVM分析了一下,发现是对象引起了死锁,thread dump和heap dump的地址是不一样的。
示例代码为:
package com.example.chapter4;
/**
* @author Cnfn
* @date 2017/11/05
*/
public class ThreadDeadlock {
static class SyncAddRunnable implements Runnable {
int a, b;
public SyncAddRunnable(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (Integer.valueOf(a)) {
synchronized (Integer.valueOf(b)) {
System.out.println(a + b);
}
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; ++i) {
new Thread(new SyncAddRunnable(1, 2)).start();
new Thread(new SyncAddRunnable(2, 1)).start();
}
}
}
则运行示例代码,Integer.valueOf(1)
和Integer.valueOf(2)
会造成死锁。但是线程转储和堆转储的地址不同。
线程转储:
堆转储:
但是 jstack
命令结果匹配堆转储:
那么,为什么 VisualVM 的线程转储与堆转储不匹配?为什么 jstack
结果匹配 VisualVM 的堆转储?
或者,我有什么问题?
谢谢~~~
PS: 我再次执行程序,并将应用程序快照、堆转储、线程转储和jstack 日志上传到Google Drive
转储中的对象 ID 是此对象在 Java 堆中的地址。
GC 可以在堆中移动对象。地址已更改的事实意味着在您 运行 jstack 和您使用 VisualVM 进行线程转储之间存在 GC。
我写了一个死锁的例子代码,然后用VisualVM分析了一下,发现是对象引起了死锁,thread dump和heap dump的地址是不一样的。
示例代码为:
package com.example.chapter4;
/**
* @author Cnfn
* @date 2017/11/05
*/
public class ThreadDeadlock {
static class SyncAddRunnable implements Runnable {
int a, b;
public SyncAddRunnable(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public void run() {
synchronized (Integer.valueOf(a)) {
synchronized (Integer.valueOf(b)) {
System.out.println(a + b);
}
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 100; ++i) {
new Thread(new SyncAddRunnable(1, 2)).start();
new Thread(new SyncAddRunnable(2, 1)).start();
}
}
}
则运行示例代码,Integer.valueOf(1)
和Integer.valueOf(2)
会造成死锁。但是线程转储和堆转储的地址不同。
线程转储:
堆转储:
但是 jstack
命令结果匹配堆转储:
那么,为什么 VisualVM 的线程转储与堆转储不匹配?为什么 jstack
结果匹配 VisualVM 的堆转储?
或者,我有什么问题?
谢谢~~~
PS: 我再次执行程序,并将应用程序快照、堆转储、线程转储和jstack 日志上传到Google Drive
转储中的对象 ID 是此对象在 Java 堆中的地址。
GC 可以在堆中移动对象。地址已更改的事实意味着在您 运行 jstack 和您使用 VisualVM 进行线程转储之间存在 GC。