Today I installed VisualVM 1.3.3 (the newest released version from visualvm.java.net). However, it appears that CPU Sampling Function is automatically disabled.
When I debug the VisualVM 1.3.3 through NetBeans, it appears the following exception information.
NoSuchFieldException of (Class Long[])getThreadCpuTime()
I searched the resource code and find that :
- in VisualVM 1.3.3, three new source files are added in plugin folder “Sample/CPU”. It appears that some detailed CPU usage information is available in the 1.3.3 version.
- in the new-added source “ThreadsCPU.java”, line 55. It writes that method “getThreadCpuTime” of ThreadMXBean is called, and expected return type is “long[]”. In contrast, in VisualVM 1.3.2 and former version, there is no such new code.
Interestingly, I found that there is “//NOI18N” comment in the end of the code like follows:
public ThreadsCPUInfo getThreadsCPUInfo() throws MBeanException, ReflectionException, IOException, InstanceNotFoundException {
long[] ids = threadBean.getAllThreadIds();
ThreadInfo[] tids = threadBean.getThreadInfo(ids);
Object[] args = new Object[] {ids};
String[] sigs = new String[] {"[J"}; // NOI18N
long[] tinfo = (long[])connection.invoke(THREAD_NAME, "getThreadCpuTime", args, sigs); // NOI18N
long time = System.currentTimeMillis();
return new ThreadsCPUInfo(time,tids,tinfo);
}
So let’s have a look at the javaDoc of JDK itself.
If we open the javadoc of OpenJDK, we can easily find that there is no such method in ThreadMXBean:
getThreadCpuTime
long getThreadCpuTime(long id)
Returns the total CPU time for a thread of the specified ID in nanoseconds. The returned value is of nanoseconds precision but not necessarily nanoseconds accuracy. If the implementation distinguishes between user mode time and system mode time, the returned CPU time is the amount of time that the thread has executed in user mode or system mode.
If the thread of the specified ID is not alive or does not exist, this method returns -1. If CPU time measurement is disabled, this method returns -1. A thread is alive if it has been started and has not yet died.
If CPU time measurement is enabled after the thread has started, the Java virtual machine implementation may choose any time up to and including the time that the capability is enabled as the point where CPU time measurement starts.
Parameters:
id - the thread ID of a thread
Returns:
the total CPU time for a thread of the specified ID if the thread of the specified ID exists, the thread is alive, and CPU time measurement is enabled; -1 otherwise.
Throws:
IllegalArgumentException - if id <= 0 .
UnsupportedOperationException - if the Java virtual machine does not support CPU time measurement for other threads.
See Also:
getThreadUserTime(long), isThreadCpuTimeSupported(), isThreadCpuTimeEnabled(), setThreadCpuTimeEnabled(boolean)
but if we open Sun Jdk (newer than 6u25), we can find the following hint:
getThreadCpuTime
long[] getThreadCpuTime(long[] ids)
Returns the total CPU time for each thread whose ID is in the input array ids in nanoseconds. The returned values are of nanoseconds precision but not necessarily nanoseconds accuracy.
This method is equivalent to calling the ThreadMXBean.getThreadCpuTime(long) method for each thread ID in the input array ids and setting the returned value in the corresponding element of the returned array.
Parameters:
ids - an array of thread IDs.
Returns:
an array of long values, each of which is the amount of CPU time the thread whose ID is in the corresponding element of the input array of IDs has used, if the thread of a specified ID exists, the thread is alive, and CPU time measurement is enabled; -1 otherwise.
Throws:
NullPointerException - if ids is null
IllegalArgumentException - if any element in the input array ids is <= 0.
UnsupportedOperationException - if the Java virtual machine implementation does not support CPU time measurement.
See Also:
ThreadMXBean.getThreadCpuTime(long), getThreadUserTime(long[]), ThreadMXBean.isThreadCpuTimeSupported(), ThreadMXBean.isThreadCpuTimeEnabled(), ThreadMXBean.setThreadCpuTimeEnabled(boolean)
So if users’ JDK is OpenJDK, or older version JDK (< 6u25), the “NoSuchMethodException” will definitely occured!
But the problem is WHY THE WHOLE CPU SAMPLING FUNCTION IS DISABLED ?
Let’s look at where the ThreadsCPU.java is invoked. It is in SampleImpl.java, line 551. Here we can easily find that the try-catch structure is so strong that normal logics are broken down.
tcpu = new ThreadsCPU(ti.getThreadMXBean(), JmxModelFactory.getJmxModelFor(application).getMBeanServerConnection());
try {
tcpu.getThreadsCPUInfo();
} catch (Exception ex) {
tcpu = null;
throw new RuntimeException(ex);
}
So let’s make some tiny change to it, as follows:
tcpu = new ThreadsCPU(ti.getThreadMXBean(), JmxModelFactory.getJmxModelFor(application).getMBeanServerConnection());
try {
tcpu.getThreadsCPUInfo();
} catch (Exception ex) {
tcpu = null;
//the following line is parsed by
//@Author: cnkmym
//@Date 2011-11-29
//@Reason: old_version of JDK does not support new method used in thie line, so all CPU_Sampling function is diabled.
//throw new RuntimeException(ex);
if (!ex.getClass().isAssignableFrom(NoSuchMethodException.class)) {
throw new RuntimeException(ex);
}
}
OK, we are DONE!
Now if users’ JDK does not support new getThreadCpuTime method, users can AT LEAST use functions same with VisualVM (Version 1.3.2).
没有评论:
发表评论