8231209: [REDO] ThreadMXBean::getThreadAllocatedBytes() can be quicker for self thread

Add com.sun.management.getCurrentThreadAllocatedBytes, implement getThreadAllocatedBytes(long) independent of getThreadAllocatedBytes(long[])

Reviewed-by: mchung, dholmes, sspitsyn
This commit is contained in:
Paul Hohensee 2019-09-25 15:22:33 -07:00
parent 916bbc23b7
commit 1bce27d402
11 changed files with 335 additions and 133 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -51,7 +51,8 @@ enum {
JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA
JMM_VERSION_1_2_2 = 0x20010202, JMM_VERSION_1_2_2 = 0x20010202,
JMM_VERSION_2 = 0x20020000, // JDK 10 JMM_VERSION_2 = 0x20020000, // JDK 10
JMM_VERSION = 0x20020000 JMM_VERSION_3 = 0x20030000, // JDK 14
JMM_VERSION = JMM_VERSION_3
}; };
typedef struct { typedef struct {
@ -239,6 +240,9 @@ typedef struct jmmInterface_1_ {
jobject (JNICALL *GetMemoryPoolUsage) (JNIEnv* env, jobject pool); jobject (JNICALL *GetMemoryPoolUsage) (JNIEnv* env, jobject pool);
jobject (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv* env, jobject pool); jobject (JNICALL *GetPeakMemoryPoolUsage) (JNIEnv* env, jobject pool);
jlong (JNICALL *GetOneThreadAllocatedMemory)
(JNIEnv *env,
jlong thread_id);
void (JNICALL *GetThreadAllocatedMemory) void (JNICALL *GetThreadAllocatedMemory)
(JNIEnv *env, (JNIEnv *env,
jlongArray ids, jlongArray ids,

View file

@ -2068,6 +2068,31 @@ jlong Management::ticks_to_ms(jlong ticks) {
} }
#endif // INCLUDE_MANAGEMENT #endif // INCLUDE_MANAGEMENT
// Gets the amount of memory allocated on the Java heap for a single thread.
// Returns -1 if the thread does not exist or has terminated.
JVM_ENTRY(jlong, jmm_GetOneThreadAllocatedMemory(JNIEnv *env, jlong thread_id))
if (thread_id < 0) {
THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
"Invalid thread ID", -1);
}
if (thread_id == 0) {
// current thread
if (THREAD->is_Java_thread()) {
return ((JavaThread*)THREAD)->cooked_allocated_bytes();
}
return -1;
}
ThreadsListHandle tlh;
JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
if (java_thread != NULL) {
return java_thread->cooked_allocated_bytes();
}
return -1;
JVM_END
// Gets an array containing the amount of memory allocated on the Java // Gets an array containing the amount of memory allocated on the Java
// heap for a set of threads (in bytes). Each element of the array is // heap for a set of threads (in bytes). Each element of the array is
// the amount of memory allocated for the thread ID specified in the // the amount of memory allocated for the thread ID specified in the
@ -2192,6 +2217,7 @@ const struct jmmInterface_1_ jmm_interface = {
jmm_GetMemoryManagers, jmm_GetMemoryManagers,
jmm_GetMemoryPoolUsage, jmm_GetMemoryPoolUsage,
jmm_GetPeakMemoryPoolUsage, jmm_GetPeakMemoryPoolUsage,
jmm_GetOneThreadAllocatedMemory,
jmm_GetThreadAllocatedMemory, jmm_GetThreadAllocatedMemory,
jmm_GetMemoryUsage, jmm_GetMemoryUsage,
jmm_GetLongAttribute, jmm_GetLongAttribute,

View file

@ -160,7 +160,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* *
* @return an array of {@code long}, each is a thread ID. * @return an array of {@code long}, each is a thread ID.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
*/ */
@ -199,7 +199,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* it does not exist. * it does not exist.
* *
* @throws IllegalArgumentException if {@code id <= 0}. * @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
*/ */
@ -237,7 +237,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* *
* @throws IllegalArgumentException if any element in the input array * @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <= 0}. * {@code ids} is {@code <= 0}.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
*/ */
@ -284,7 +284,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* *
* @throws IllegalArgumentException if {@code id <= 0}. * @throws IllegalArgumentException if {@code id <= 0}.
* @throws IllegalArgumentException if {@code maxDepth is negative}. * @throws IllegalArgumentException if {@code maxDepth is negative}.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* *
@ -337,7 +337,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @throws IllegalArgumentException if {@code maxDepth is negative}. * @throws IllegalArgumentException if {@code maxDepth is negative}.
* @throws IllegalArgumentException if any element in the input array * @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <= 0}. * {@code ids} is {@code <= 0}.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* *
@ -360,7 +360,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return {@code true} if thread contention monitoring is enabled; * @return {@code true} if thread contention monitoring is enabled;
* {@code false} otherwise. * {@code false} otherwise.
* *
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine does not support thread contention monitoring. * machine does not support thread contention monitoring.
* *
* @see #isThreadContentionMonitoringSupported * @see #isThreadContentionMonitoringSupported
@ -374,10 +374,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @param enable {@code true} to enable; * @param enable {@code true} to enable;
* {@code false} to disable. * {@code false} to disable.
* *
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support thread contention monitoring. * virtual machine does not support thread contention monitoring.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("control"). * ManagementPermission("control").
* *
@ -394,7 +394,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* the current thread has executed in user mode or system mode. * the current thread has executed in user mode or system mode.
* *
* <p> * <p>
* This is a convenient method for local management use and is * This is a convenience method for local management use and is
* equivalent to calling: * equivalent to calling:
* <blockquote><pre> * <blockquote><pre>
* {@link #getThreadCpuTime getThreadCpuTime}(Thread.currentThread().getId()); * {@link #getThreadCpuTime getThreadCpuTime}(Thread.currentThread().getId());
@ -403,7 +403,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return the total CPU time for the current thread if CPU time * @return the total CPU time for the current thread if CPU time
* measurement is enabled; {@code -1} otherwise. * measurement is enabled; {@code -1} otherwise.
* *
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for * virtual machine does not support CPU time measurement for
* the current thread. * the current thread.
* *
@ -421,7 +421,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* not necessarily nanoseconds accuracy. * not necessarily nanoseconds accuracy.
* *
* <p> * <p>
* This is a convenient method for local management use and is * This is a convenience method for local management use and is
* equivalent to calling: * equivalent to calling:
* <blockquote><pre> * <blockquote><pre>
* {@link #getThreadUserTime getThreadUserTime}(Thread.currentThread().getId()); * {@link #getThreadUserTime getThreadUserTime}(Thread.currentThread().getId());
@ -430,7 +430,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return the user-level CPU time for the current thread if CPU time * @return the user-level CPU time for the current thread if CPU time
* measurement is enabled; {@code -1} otherwise. * measurement is enabled; {@code -1} otherwise.
* *
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for * virtual machine does not support CPU time measurement for
* the current thread. * the current thread.
* *
@ -467,7 +467,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* {@code -1} otherwise. * {@code -1} otherwise.
* *
* @throws IllegalArgumentException if {@code id <= 0}. * @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for * virtual machine does not support CPU time measurement for
* other threads. * other threads.
* *
@ -502,7 +502,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* {@code -1} otherwise. * {@code -1} otherwise.
* *
* @throws IllegalArgumentException if {@code id <= 0}. * @throws IllegalArgumentException if {@code id <= 0}.
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for * virtual machine does not support CPU time measurement for
* other threads. * other threads.
* *
@ -548,7 +548,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return {@code true} if thread CPU time measurement is enabled; * @return {@code true} if thread CPU time measurement is enabled;
* {@code false} otherwise. * {@code false} otherwise.
* *
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine does not support CPU time measurement for other threads * machine does not support CPU time measurement for other threads
* nor for the current thread. * nor for the current thread.
* *
@ -564,11 +564,11 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @param enable {@code true} to enable; * @param enable {@code true} to enable;
* {@code false} to disable. * {@code false} to disable.
* *
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine does not support CPU time measurement for * virtual machine does not support CPU time measurement for
* any threads nor for the current thread. * any threads nor for the current thread.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("control"). * ManagementPermission("control").
* *
@ -604,7 +604,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return an array of IDs of the threads that are monitor * @return an array of IDs of the threads that are monitor
* deadlocked, if any; {@code null} otherwise. * deadlocked, if any; {@code null} otherwise.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* *
@ -616,7 +616,7 @@ public interface ThreadMXBean extends PlatformManagedObject {
* Resets the peak thread count to the current number of * Resets the peak thread count to the current number of
* live threads. * live threads.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("control"). * ManagementPermission("control").
* *
@ -642,10 +642,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* deadlocked waiting for object monitors or ownable synchronizers, if any; * deadlocked waiting for object monitors or ownable synchronizers, if any;
* {@code null} otherwise. * {@code null} otherwise.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine does not support monitoring of ownable synchronizer usage. * machine does not support monitoring of ownable synchronizer usage.
* *
* @see #isSynchronizerUsageSupported * @see #isSynchronizerUsageSupported
@ -704,10 +704,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* information about a thread whose ID is in the corresponding * information about a thread whose ID is in the corresponding
* element of the input array of IDs. * element of the input array of IDs.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException * @throws UnsupportedOperationException
* <ul> * <ul>
* <li>if {@code lockedMonitors} is {@code true} but * <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring * the Java virtual machine does not support monitoring
@ -794,10 +794,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* element of the input array of IDs. * element of the input array of IDs.
* *
* @throws IllegalArgumentException if {@code maxDepth} is negative. * @throws IllegalArgumentException if {@code maxDepth} is negative.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException * @throws UnsupportedOperationException
* <ul> * <ul>
* <li>if {@code lockedMonitors} is {@code true} but * <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring * the Java virtual machine does not support monitoring
@ -835,10 +835,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* *
* @return an array of {@link ThreadInfo} for all live threads. * @return an array of {@link ThreadInfo} for all live threads.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException * @throws UnsupportedOperationException
* <ul> * <ul>
* <li>if {@code lockedMonitors} is {@code true} but * <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring * the Java virtual machine does not support monitoring
@ -884,10 +884,10 @@ public interface ThreadMXBean extends PlatformManagedObject {
* @return an array of {@link ThreadInfo} for all live threads. * @return an array of {@link ThreadInfo} for all live threads.
* *
* @throws IllegalArgumentException if {@code maxDepth} is negative. * @throws IllegalArgumentException if {@code maxDepth} is negative.
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("monitor"). * ManagementPermission("monitor").
* @throws java.lang.UnsupportedOperationException * @throws UnsupportedOperationException
* <ul> * <ul>
* <li>if {@code lockedMonitors} is {@code true} but * <li>if {@code lockedMonitors} is {@code true} but
* the Java virtual machine does not support monitoring * the Java virtual machine does not support monitoring

View file

@ -29,6 +29,7 @@ import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo; import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean; import java.lang.management.ThreadMXBean;
import javax.management.ObjectName; import javax.management.ObjectName;
import java.util.Objects;
/** /**
* Implementation for java.lang.management.ThreadMXBean as well as providing the * Implementation for java.lang.management.ThreadMXBean as well as providing the
@ -112,11 +113,15 @@ public class ThreadImpl implements ThreadMXBean {
return cpuTimeEnabled; return cpuTimeEnabled;
} }
protected boolean isThreadAllocatedMemoryEnabled() { private void ensureThreadAllocatedMemorySupported() {
if (!isThreadAllocatedMemorySupported()) { if (!isThreadAllocatedMemorySupported()) {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
"Thread allocated memory measurement is not supported"); "Thread allocated memory measurement is not supported.");
} }
}
protected boolean isThreadAllocatedMemoryEnabled() {
ensureThreadAllocatedMemorySupported();
return allocatedMemoryEnabled; return allocatedMemoryEnabled;
} }
@ -155,16 +160,18 @@ public class ThreadImpl implements ThreadMXBean {
return getThreadInfo(ids, 0); return getThreadInfo(ids, 0);
} }
private void verifyThreadIds(long[] ids) { private void verifyThreadId(long id) {
if (ids == null) { if (id <= 0) {
throw new NullPointerException("Null ids parameter."); throw new IllegalArgumentException(
"Invalid thread ID parameter: " + id);
}
} }
private void verifyThreadIds(long[] ids) {
Objects.requireNonNull(ids);
for (int i = 0; i < ids.length; i++) { for (int i = 0; i < ids.length; i++) {
if (ids[i] <= 0) { verifyThreadId(ids[i]);
throw new IllegalArgumentException(
"Invalid thread ID parameter: " + ids[i]);
}
} }
} }
@ -342,26 +349,41 @@ public class ThreadImpl implements ThreadMXBean {
} }
} }
protected long getCurrentThreadAllocatedBytes() {
if (isThreadAllocatedMemoryEnabled()) {
return getThreadAllocatedMemory0(0);
}
return -1;
}
private boolean verifyThreadAllocatedMemory(long id) {
verifyThreadId(id);
return isThreadAllocatedMemoryEnabled();
}
protected long getThreadAllocatedBytes(long id) { protected long getThreadAllocatedBytes(long id) {
long[] ids = new long[1]; boolean verified = verifyThreadAllocatedMemory(id);
ids[0] = id;
final long[] sizes = getThreadAllocatedBytes(ids); if (verified) {
return sizes[0]; return getThreadAllocatedMemory0(
Thread.currentThread().getId() == id ? 0 : id);
}
return -1;
} }
private boolean verifyThreadAllocatedMemory(long[] ids) { private boolean verifyThreadAllocatedMemory(long[] ids) {
verifyThreadIds(ids); verifyThreadIds(ids);
// check if Thread allocated memory measurement is supported.
if (!isThreadAllocatedMemorySupported()) {
throw new UnsupportedOperationException(
"Thread allocated memory measurement is not supported.");
}
return isThreadAllocatedMemoryEnabled(); return isThreadAllocatedMemoryEnabled();
} }
protected long[] getThreadAllocatedBytes(long[] ids) { protected long[] getThreadAllocatedBytes(long[] ids) {
Objects.requireNonNull(ids);
if (ids.length == 1) {
long size = getThreadAllocatedBytes(ids[0]);
return new long[] { size };
}
boolean verified = verifyThreadAllocatedMemory(ids); boolean verified = verifyThreadAllocatedMemory(ids);
long[] sizes = new long[ids.length]; long[] sizes = new long[ids.length];
@ -374,10 +396,7 @@ public class ThreadImpl implements ThreadMXBean {
} }
protected void setThreadAllocatedMemoryEnabled(boolean enable) { protected void setThreadAllocatedMemoryEnabled(boolean enable) {
if (!isThreadAllocatedMemorySupported()) { ensureThreadAllocatedMemorySupported();
throw new UnsupportedOperationException(
"Thread allocated memory measurement is not supported.");
}
Util.checkControlAccess(); Util.checkControlAccess();
synchronized (this) { synchronized (this) {
@ -511,6 +530,7 @@ public class ThreadImpl implements ThreadMXBean {
private static native void getThreadTotalCpuTime1(long[] ids, long[] result); private static native void getThreadTotalCpuTime1(long[] ids, long[] result);
private static native long getThreadUserCpuTime0(long id); private static native long getThreadUserCpuTime0(long id);
private static native void getThreadUserCpuTime1(long[] ids, long[] result); private static native void getThreadUserCpuTime1(long[] ids, long[] result);
private static native long getThreadAllocatedMemory0(long id);
private static native void getThreadAllocatedMemory1(long[] ids, long[] result); private static native void getThreadAllocatedMemory1(long[] ids, long[] result);
private static native void setThreadCpuTimeEnabled0(boolean enable); private static native void setThreadCpuTimeEnabled0(boolean enable);
private static native void setThreadAllocatedMemoryEnabled0(boolean enable); private static native void setThreadAllocatedMemoryEnabled0(boolean enable);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -94,6 +94,13 @@ Java_sun_management_ThreadImpl_getThreadUserCpuTime1
JNI_FALSE /* user */); JNI_FALSE /* user */);
} }
JNIEXPORT jlong JNICALL
Java_sun_management_ThreadImpl_getThreadAllocatedMemory0
(JNIEnv *env, jclass cls, jlong tid)
{
return jmm_interface->GetOneThreadAllocatedMemory(env, tid);
}
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_sun_management_ThreadImpl_getThreadAllocatedMemory1 Java_sun_management_ThreadImpl_getThreadAllocatedMemory1
(JNIEnv *env, jclass cls, jlongArray ids, jlongArray sizeArray) (JNIEnv *env, jclass cls, jlongArray ids, jlongArray sizeArray)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -61,7 +61,7 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* @throws NullPointerException if {@code ids} is {@code null} * @throws NullPointerException if {@code ids} is {@code null}
* @throws IllegalArgumentException if any element in the input array * @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <=} {@code 0}. * {@code ids} is {@code <=} {@code 0}.
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine implementation does not support CPU time * virtual machine implementation does not support CPU time
* measurement. * measurement.
* *
@ -95,7 +95,7 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* @throws NullPointerException if {@code ids} is {@code null} * @throws NullPointerException if {@code ids} is {@code null}
* @throws IllegalArgumentException if any element in the input array * @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <=} {@code 0}. * {@code ids} is {@code <=} {@code 0}.
* @throws java.lang.UnsupportedOperationException if the Java * @throws UnsupportedOperationException if the Java
* virtual machine implementation does not support CPU time * virtual machine implementation does not support CPU time
* measurement. * measurement.
* *
@ -109,13 +109,50 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
/** /**
* Returns an approximation of the total amount of memory, in bytes, * Returns an approximation of the total amount of memory, in bytes,
* allocated in heap memory for the thread of the specified ID. * allocated in heap memory for the current thread.
* The returned value is an approximation because some Java virtual machine
* implementations may use object allocation mechanisms that result in a
* delay between the time an object is allocated and the time its size is
* recorded.
*
* <p>
* This is a convenience method for local management use and is
* equivalent to calling:
* <blockquote><pre>
* {@link #getThreadAllocatedBytes getThreadAllocatedBytes}(Thread.currentThread().getId());
* </pre></blockquote>
*
* @implSpec The default implementation throws
* {@code UnsupportedOperationException}.
*
* @return an approximation of the total memory allocated, in bytes, in
* heap memory for the current thread
* if thread memory allocation measurement is enabled;
* {@code -1} otherwise.
*
* @throws UnsupportedOperationException if the Java virtual
* machine implementation does not support thread memory allocation
* measurement.
*
* @see #isThreadAllocatedMemorySupported
* @see #isThreadAllocatedMemoryEnabled
* @see #setThreadAllocatedMemoryEnabled
*
* @since 14
*/
public default long getCurrentThreadAllocatedBytes() {
throw new UnsupportedOperationException();
}
/**
* Returns an approximation of the total amount of memory, in bytes,
* allocated in heap memory for the thread with the specified ID.
* The returned value is an approximation because some Java virtual machine * The returned value is an approximation because some Java virtual machine
* implementations may use object allocation mechanisms that result in a * implementations may use object allocation mechanisms that result in a
* delay between the time an object is allocated and the time its size is * delay between the time an object is allocated and the time its size is
* recorded. * recorded.
* <p> * <p>
* If the thread of the specified ID is not alive or does not exist, * If the thread with the specified ID is not alive or does not exist,
* this method returns {@code -1}. If thread memory allocation measurement * this method returns {@code -1}. If thread memory allocation measurement
* is disabled, this method returns {@code -1}. * is disabled, this method returns {@code -1}.
* A thread is alive if it has been started and has not yet died. * A thread is alive if it has been started and has not yet died.
@ -127,13 +164,13 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* *
* @param id the thread ID of a thread * @param id the thread ID of a thread
* @return an approximation of the total memory allocated, in bytes, in * @return an approximation of the total memory allocated, in bytes, in
* heap memory for a thread of the specified ID * heap memory for the thread with the specified ID
* if the thread of the specified ID exists, the thread is alive, * if the thread with the specified ID exists, the thread is alive,
* and thread memory allocation measurement is enabled; * and thread memory allocation measurement is enabled;
* {@code -1} otherwise. * {@code -1} otherwise.
* *
* @throws IllegalArgumentException if {@code id} {@code <=} {@code 0}. * @throws IllegalArgumentException if {@code id} {@code <=} {@code 0}.
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine implementation does not support thread memory allocation * machine implementation does not support thread memory allocation
* measurement. * measurement.
* *
@ -165,7 +202,7 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* @throws NullPointerException if {@code ids} is {@code null} * @throws NullPointerException if {@code ids} is {@code null}
* @throws IllegalArgumentException if any element in the input array * @throws IllegalArgumentException if any element in the input array
* {@code ids} is {@code <=} {@code 0}. * {@code ids} is {@code <=} {@code 0}.
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine implementation does not support thread memory allocation * machine implementation does not support thread memory allocation
* measurement. * measurement.
* *
@ -194,7 +231,7 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* @return {@code true} if thread memory allocation measurement is enabled; * @return {@code true} if thread memory allocation measurement is enabled;
* {@code false} otherwise. * {@code false} otherwise.
* *
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine does not support thread memory allocation measurement. * machine does not support thread memory allocation measurement.
* *
* @see #isThreadAllocatedMemorySupported * @see #isThreadAllocatedMemorySupported
@ -208,10 +245,10 @@ public interface ThreadMXBean extends java.lang.management.ThreadMXBean {
* @param enable {@code true} to enable; * @param enable {@code true} to enable;
* {@code false} to disable. * {@code false} to disable.
* *
* @throws java.lang.UnsupportedOperationException if the Java virtual * @throws UnsupportedOperationException if the Java virtual
* machine does not support thread memory allocation measurement. * machine does not support thread memory allocation measurement.
* *
* @throws java.lang.SecurityException if a security manager * @throws SecurityException if a security manager
* exists and the caller does not have * exists and the caller does not have
* ManagementPermission("control"). * ManagementPermission("control").
* *

View file

@ -57,6 +57,11 @@ public class HotSpotThreadImpl extends ThreadImpl implements ThreadMXBean {
return super.getThreadUserTime(ids); return super.getThreadUserTime(ids);
} }
@Override
public long getCurrentThreadAllocatedBytes() {
return super.getCurrentThreadAllocatedBytes();
}
@Override @Override
public long getThreadAllocatedBytes(long id) { public long getThreadAllocatedBytes(long id) {
return super.getThreadAllocatedBytes(id); return super.getThreadAllocatedBytes(id);

View file

@ -1,4 +1,4 @@
Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it This code is free software; you can redistribute it and/or modify it
@ -21,7 +21,8 @@ questions.
DESCRIPTION DESCRIPTION
Tests getThreadAllocatedBytes(long id) and getThreadAllocatedBytes(long[] ids), Tests getCurrentThreadAllocatedBytes(), getThreadAllocatedBytes(long id),
and getThreadAllocatedBytes(long[] ids),
functions of com.sun.management.ThreadMXBean functions of com.sun.management.ThreadMXBean
All methods should All methods should

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,8 @@ import nsk.monitoring.share.*;
import nsk.monitoring.ThreadMXBean.*; import nsk.monitoring.ThreadMXBean.*;
/** /**
* Tests getThreadAllocatedBytes(long id) and getThreadAllocatedBytes(long[] ids), * Tests getCurrentThreadAllocatedBytes(), getThreadAllocatedBytes(long id).
* and getThreadAllocatedBytes(long[] ids),
* functions of com.sun.management.ThreadMXBean * functions of com.sun.management.ThreadMXBean
* <p> * <p>
* All methods should * All methods should
@ -49,11 +50,31 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase {
public void run() { public void run() {
if (threadMXBean == null) if (threadMXBean == null)
return; return;
// Expect -1 if thread allocated memory is disabled
threadMXBean.setThreadAllocatedMemoryEnabled(false);
long result = threadMXBean.getCurrentThreadAllocatedBytes();
if (result != -1)
throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should "
+ "return -1 if ThreadAllocatedMemoryEnabled is set to false. "
+ "Received : " + result);
threadMXBean.setThreadAllocatedMemoryEnabled(true);
// Expect >= 0 value for current thread
result = threadMXBean.getCurrentThreadAllocatedBytes();
if (result < 0)
throw new TestFailure("Failure! getCurrentThreadAllocatedBytes() should "
+ "return >= 0 value for current thread. Received : " + result);
// Expect >= 0 value for current thread from getThreadAllocatedBytes(id)
result = threadMXBean.getThreadAllocatedBytes(Thread.currentThread().getId());
if (result < 0)
throw new TestFailure("Failure! getThreadAllocatedBytes(id) should "
+ "return >= 0 value for current thread. Received : " + result);
MXBeanTestThread thread = new MXBeanTestThread(); MXBeanTestThread thread = new MXBeanTestThread();
long id = thread.getId(); long id = thread.getId();
long[] idArr = new long[] { id }; long[] idArr = new long[] { id };
long result;
long[] resultArr; long[] resultArr;
// Expect -1 for not started threads // Expect -1 for not started threads
result = threadMXBean.getThreadAllocatedBytes(id); result = threadMXBean.getThreadAllocatedBytes(id);
if (result != -1) if (result != -1)
@ -80,7 +101,7 @@ public class BaseBehaviorTest extends ThreadMXBeanTestBase {
+ "Recieved : " + resultArr[0]); + "Recieved : " + resultArr[0]);
threadMXBean.setThreadAllocatedMemoryEnabled(true); threadMXBean.setThreadAllocatedMemoryEnabled(true);
// Expect > 0 value for running threads // Expect >= 0 value for running threads
result = threadMXBean.getThreadAllocatedBytes(id); result = threadMXBean.getThreadAllocatedBytes(id);
if (result < 0) if (result < 0)
throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should " throw new TestFailure("Failure! getThreadAllocatedBytes(long id) should "

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -59,6 +59,10 @@ public class ServerThreadMXBeanNew extends ServerThreadMXBean implements ThreadM
new String[] { long.class.getName() }); new String[] { long.class.getName() });
} }
public long getCurrentThreadAllocatedBytes() {
return getLongAttribute("CurrentThreadAllocatedBytes");
}
public void setThreadAllocatedMemoryEnabled(boolean enabled) { public void setThreadAllocatedMemoryEnabled(boolean enabled) {
setBooleanAttribute("ThreadAllocatedMemoryEnabled", enabled); setBooleanAttribute("ThreadAllocatedMemoryEnabled", enabled);
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/* /*
* @test * @test
* @bug 6173675 * @bug 6173675 8231209
* @summary Basic test of ThreadMXBean.getThreadAllocatedBytes * @summary Basic test of ThreadMXBean.getThreadAllocatedBytes
* @author Paul Hohensee * @author Paul Hohensee
*/ */
@ -33,9 +33,8 @@ import java.lang.management.*;
public class ThreadAllocatedMemory { public class ThreadAllocatedMemory {
private static com.sun.management.ThreadMXBean mbean = private static com.sun.management.ThreadMXBean mbean =
(com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean(); (com.sun.management.ThreadMXBean)ManagementFactory.getThreadMXBean();
private static boolean testFailed = false; private static volatile boolean done = false;
private static boolean done = false; private static volatile boolean done1 = false;
private static boolean done1 = false;
private static Object obj = new Object(); private static Object obj = new Object();
private static final int NUM_THREADS = 10; private static final int NUM_THREADS = 10;
private static Thread[] threads = new Thread[NUM_THREADS]; private static Thread[] threads = new Thread[NUM_THREADS];
@ -44,6 +43,22 @@ public class ThreadAllocatedMemory {
public static void main(String[] argv) public static void main(String[] argv)
throws Exception { throws Exception {
testSupportEnableDisable();
// Test current thread two ways
testGetCurrentThreadAllocatedBytes();
testCurrentThreadGetThreadAllocatedBytes();
// Test a single thread that is not this one
testGetThreadAllocatedBytes();
// Test many threads that are not this one
testGetThreadsAllocatedBytes();
System.out.println("Test passed");
}
private static void testSupportEnableDisable() {
if (!mbean.isThreadAllocatedMemorySupported()) { if (!mbean.isThreadAllocatedMemorySupported()) {
return; return;
} }
@ -58,10 +73,7 @@ public class ThreadAllocatedMemory {
"ThreadAllocatedMemory is expected to be disabled"); "ThreadAllocatedMemory is expected to be disabled");
} }
Thread curThread = Thread.currentThread(); long s = mbean.getCurrentThreadAllocatedBytes();
long id = curThread.getId();
long s = mbean.getThreadAllocatedBytes(id);
if (s != -1) { if (s != -1) {
throw new RuntimeException( throw new RuntimeException(
"Invalid ThreadAllocatedBytes returned = " + "Invalid ThreadAllocatedBytes returned = " +
@ -77,42 +89,93 @@ public class ThreadAllocatedMemory {
throw new RuntimeException( throw new RuntimeException(
"ThreadAllocatedMemory is expected to be enabled"); "ThreadAllocatedMemory is expected to be enabled");
} }
long size = mbean.getThreadAllocatedBytes(id);
// implementation could have started measurement when
// measurement was enabled, in which case size can be 0
if (size < 0) {
throw new RuntimeException(
"Invalid allocated bytes returned = " + size);
} }
private static void testGetCurrentThreadAllocatedBytes() {
long size = mbean.getCurrentThreadAllocatedBytes();
ensureValidSize(size);
// do some more allocation
doit(); doit();
// Expected to be size1 >= size checkResult(Thread.currentThread(), size,
long size1 = mbean.getThreadAllocatedBytes(id); mbean.getCurrentThreadAllocatedBytes());
if (size1 < size) {
throw new RuntimeException("Allocated bytes " + size1 +
" expected >= " + size);
} }
System.out.println(curThread.getName() +
" Current thread allocated bytes = " + size +
" allocated bytes = " + size1);
private static void testCurrentThreadGetThreadAllocatedBytes() {
Thread curThread = Thread.currentThread();
long id = curThread.getId();
// start threads, wait for them to block long size = mbean.getThreadAllocatedBytes(id);
ensureValidSize(size);
// do some more allocation
doit();
checkResult(curThread, size, mbean.getThreadAllocatedBytes(id));
}
private static void testGetThreadAllocatedBytes()
throws Exception {
// start a thread
done = false; done1 = false;
Thread curThread = new MyThread("MyThread");
curThread.start();
long id = curThread.getId();
// wait for thread to block after doing some allocation
waitUntilThreadBlocked(curThread);
long size = mbean.getThreadAllocatedBytes(id);
ensureValidSize(size);
// let thread go to do some more allocation
synchronized (obj) {
done = true;
obj.notifyAll();
}
// wait for thread to get going again. we don't care if we
// catch it in mid-execution or if it hasn't
// restarted after we're done sleeping.
goSleep(400);
checkResult(curThread, size, mbean.getThreadAllocatedBytes(id));
// let thread exit
synchronized (obj) {
done1 = true;
obj.notifyAll();
}
try {
curThread.join();
} catch (InterruptedException e) {
System.out.println("Unexpected exception is thrown.");
e.printStackTrace(System.out);
}
}
private static void testGetThreadsAllocatedBytes()
throws Exception {
// start threads
done = false; done1 = false;
for (int i = 0; i < NUM_THREADS; i++) { for (int i = 0; i < NUM_THREADS; i++) {
threads[i] = new MyThread("MyThread-" + i); threads[i] = new MyThread("MyThread-" + i);
threads[i].start(); threads[i].start();
} }
// threads block after doing some allocation // wait for threads to block after doing some allocation
waitUntilThreadBlocked(); waitUntilThreadsBlocked();
for (int i = 0; i < NUM_THREADS; i++) { for (int i = 0; i < NUM_THREADS; i++) {
sizes[i] = mbean.getThreadAllocatedBytes(threads[i].getId()); sizes[i] = mbean.getThreadAllocatedBytes(threads[i].getId());
ensureValidSize(sizes[i]);
} }
// let threads go and do some more allocation // let threads go to do some more allocation
synchronized (obj) { synchronized (obj) {
done = true; done = true;
obj.notifyAll(); obj.notifyAll();
@ -124,16 +187,8 @@ public class ThreadAllocatedMemory {
goSleep(400); goSleep(400);
for (int i = 0; i < NUM_THREADS; i++) { for (int i = 0; i < NUM_THREADS; i++) {
long newSize = mbean.getThreadAllocatedBytes(threads[i].getId()); checkResult(threads[i], sizes[i],
if (sizes[i] > newSize) { mbean.getThreadAllocatedBytes(threads[i].getId()));
throw new RuntimeException("TEST FAILED: " +
threads[i].getName() +
" previous allocated bytes = " + sizes[i] +
" > current allocated bytes = " + newSize);
}
System.out.println(threads[i].getName() +
" Previous allocated bytes = " + sizes[i] +
" Current allocated bytes = " + newSize);
} }
// let threads exit // let threads exit
@ -148,17 +203,30 @@ public class ThreadAllocatedMemory {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("Unexpected exception is thrown."); System.out.println("Unexpected exception is thrown.");
e.printStackTrace(System.out); e.printStackTrace(System.out);
testFailed = true;
break; break;
} }
} }
if (testFailed) {
throw new RuntimeException("TEST FAILED");
} }
System.out.println("Test passed"); private static void ensureValidSize(long size) {
// implementation could have started measurement when
// measurement was enabled, in which case size can be 0
if (size < 0) {
throw new RuntimeException(
"Invalid allocated bytes returned = " + size);
}
} }
private static void checkResult(Thread curThread,
long prev_size, long curr_size) {
if (curr_size < prev_size) {
throw new RuntimeException("Allocated bytes " + curr_size +
" expected >= " + prev_size);
}
System.out.println(curThread.getName() +
" Previous allocated bytes = " + prev_size +
" Current allocated bytes = " + curr_size);
}
private static void goSleep(long ms) throws Exception { private static void goSleep(long ms) throws Exception {
try { try {
@ -169,7 +237,18 @@ public class ThreadAllocatedMemory {
} }
} }
private static void waitUntilThreadBlocked() private static void waitUntilThreadBlocked(Thread thread)
throws Exception {
while (true) {
goSleep(100);
ThreadInfo info = mbean.getThreadInfo(thread.getId());
if (info.getThreadState() == Thread.State.WAITING) {
break;
}
}
}
private static void waitUntilThreadsBlocked()
throws Exception { throws Exception {
int count = 0; int count = 0;
while (count != NUM_THREADS) { while (count != NUM_THREADS) {
@ -210,7 +289,6 @@ public class ThreadAllocatedMemory {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("Unexpected exception is thrown."); System.out.println("Unexpected exception is thrown.");
e.printStackTrace(System.out); e.printStackTrace(System.out);
testFailed = true;
break; break;
} }
} }
@ -225,7 +303,7 @@ public class ThreadAllocatedMemory {
" ThreadAllocatedBytes = " + size2); " ThreadAllocatedBytes = " + size2);
if (size1 > size2) { if (size1 > size2) {
throw new RuntimeException("TEST FAILED: " + getName() + throw new RuntimeException(getName() +
" ThreadAllocatedBytes = " + size1 + " ThreadAllocatedBytes = " + size1 +
" > ThreadAllocatedBytes = " + size2); " > ThreadAllocatedBytes = " + size2);
} }
@ -237,7 +315,6 @@ public class ThreadAllocatedMemory {
} catch (InterruptedException e) { } catch (InterruptedException e) {
System.out.println("Unexpected exception is thrown."); System.out.println("Unexpected exception is thrown.");
e.printStackTrace(System.out); e.printStackTrace(System.out);
testFailed = true;
break; break;
} }
} }