本文主要研究一下openjdk的BufferPoolMXBean
java.management/java/lang/management/PlatformManagedObject.java
public interface PlatformManagedObject { /** * Returns an {@link ObjectName ObjectName} instance representing * the object name of this platform managed object. * * @return an {@link ObjectName ObjectName} instance representing * the object name of this platform managed object. */ public ObjectName getObjectName(); }
PlatformManagedObject接口定义了getObjectName方法用于返回ObjectName
java.management/java/lang/management/BufferPoolMXBean.java
public interface BufferPoolMXBean extends PlatformManagedObject { /** * Returns the name representing this buffer pool. * * @return The name of this buffer pool. */ String getName(); /** * Returns an estimate of the number of buffers in the pool. * * @return An estimate of the number of buffers in this pool */ long getCount(); /** * Returns an estimate of the total capacity of the buffers in this pool. * A buffer's capacity is the number of elements it contains and the value * returned by this method is an estimate of the total capacity of buffers * in the pool in bytes. * * @return An estimate of the total capacity of the buffers in this pool * in bytes */ long getTotalCapacity(); /** * Returns an estimate of the memory that the Java virtual machine is using * for this buffer pool. The value returned by this method may differ * from the estimate of the total {@link #getTotalCapacity capacity} of * the buffers in this pool. This difference is explained by alignment, * memory allocator, and other implementation specific reasons. * * @return An estimate of the memory that the Java virtual machine is using * for this buffer pool in bytes, or {@code -1L} if an estimate of * the memory usage is not available */ long getMemoryUsed(); }
java.management/sun/management/ManagementFactoryHelper.java
public class ManagementFactoryHelper { static { // make sure that the management lib is loaded within // java.lang.management.ManagementFactory jdk.internal.misc.Unsafe.getUnsafe().ensureClassInitialized(ManagementFactory.class); } private static final VMManagement jvm = new VMManagementImpl(); private ManagementFactoryHelper() {}; public static VMManagement getVMManagement() { return jvm; } static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; private static ClassLoadingImpl classMBean = null; private static MemoryImpl memoryMBean = null; private static ThreadImpl threadMBean = null; private static RuntimeImpl runtimeMBean = null; private static CompilationImpl compileMBean = null; private static BaseOperatingSystemImpl osMBean = null; //...... private static List<BufferPoolMXBean> bufferPools = null; public static synchronized List<BufferPoolMXBean> getBufferPoolMXBeans() { if (bufferPools == null) { bufferPools = new ArrayList<>(2); bufferPools.add(createBufferPoolMXBean(SharedSecrets.getJavaNioAccess() .getDirectBufferPool())); bufferPools.add(createBufferPoolMXBean(sun.nio.ch.FileChannelImpl .getMappedBufferPool())); } return bufferPools; } private static BufferPoolMXBean createBufferPoolMXBean(final JavaNioAccess.BufferPool pool) { return new BufferPoolMXBean() { private volatile ObjectName objname; // created lazily @Override public ObjectName getObjectName() { ObjectName result = objname; if (result == null) { synchronized (this) { result = objname; if (result == null) { result = Util.newObjectName(BUFFER_POOL_MXBEAN_NAME + ",name=" + pool.getName()); objname = result; } } } return result; } @Override public String getName() { return pool.getName(); } @Override public long getCount() { return pool.getCount(); } @Override public long getTotalCapacity() { return pool.getTotalCapacity(); } @Override public long getMemoryUsed() { return pool.getMemoryUsed(); } }; } //...... }
java.base/jdk/internal/access/JavaNioAccess.java
public interface JavaNioAccess { /** * Provides access to information on buffer usage. */ interface BufferPool { String getName(); long getCount(); long getTotalCapacity(); long getMemoryUsed(); } BufferPool getDirectBufferPool(); }
java.base/jdk/internal/access/SharedSecrets.java
public class SharedSecrets { private static final Unsafe unsafe = Unsafe.getUnsafe(); private static JavaUtilJarAccess javaUtilJarAccess; private static JavaLangAccess javaLangAccess; private static JavaLangModuleAccess javaLangModuleAccess; private static JavaLangInvokeAccess javaLangInvokeAccess; private static JavaLangRefAccess javaLangRefAccess; private static JavaIOAccess javaIOAccess; private static JavaNetInetAddressAccess javaNetInetAddressAccess; private static JavaNetHttpCookieAccess javaNetHttpCookieAccess; private static JavaNetSocketAccess javaNetSocketAccess; private static JavaNetUriAccess javaNetUriAccess; private static JavaNetURLAccess javaNetURLAccess; private static JavaNetURLClassLoaderAccess javaNetURLClassLoaderAccess; private static JavaNioAccess javaNioAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaIOFilePermissionAccess javaIOFilePermissionAccess; private static JavaSecurityAccess javaSecurityAccess; private static JavaUtilZipFileAccess javaUtilZipFileAccess; private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess; private static JavaAWTAccess javaAWTAccess; private static JavaAWTFontAccess javaAWTFontAccess; private static JavaBeansAccess javaBeansAccess; private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; private static JavaObjectInputFilterAccess javaObjectInputFilterAccess; private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess; private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; //...... public static void setJavaNioAccess(JavaNioAccess jna) { javaNioAccess = jna; } public static JavaNioAccess getJavaNioAccess() { if (javaNioAccess == null) { // Ensure java.nio.Buffer is initialized, which provides the // shared secret. unsafe.ensureClassInitialized(java.nio.Buffer.class); } return javaNioAccess; } //...... }
java.base/java/nio/Buffer.java
public abstract class Buffer { // Cached unsafe-access object static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** * The characteristics of Spliterators that traverse and split elements * maintained in Buffers. */ static final int SPLITERATOR_CHARACTERISTICS = Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED; // Invariants: mark <= position <= limit <= capacity private int mark = -1; private int position = 0; private int limit; private int capacity; // Used by heap byte buffers or direct buffers with Unsafe access // For heap byte buffers this field will be the address relative to the // array base address and offset into that array. The address might // not align on a word boundary for slices, nor align at a long word // (8 byte) boundary for byte[] allocations on 32-bit systems. // For direct buffers it is the start address of the memory region. The // address might not align on a word boundary for slices, nor when created // using JNI, see NewDirectByteBuffer(void*, long). // Should ideally be declared final // NOTE: hoisted here for speed in JNI GetDirectBufferAddress long address; //...... static { // setup access to this package in SharedSecrets SharedSecrets.setJavaNioAccess( new JavaNioAccess() { @Override public JavaNioAccess.BufferPool getDirectBufferPool() { return Bits.BUFFER_POOL; } }); } }
java.base/sun/nio/ch/FileChannelImpl.java
public class FileChannelImpl extends FileChannel { // Memory allocation size for mapping buffers private static final long allocationGranularity; // Access to FileDescriptor internals private static final JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); // Used to make native read and write calls private final FileDispatcher nd; // File descriptor private final FileDescriptor fd; //...... // -- Memory-mapped buffers -- private static class Unmapper implements Runnable { // may be required to close file private static final NativeDispatcher nd = new FileDispatcherImpl(); // keep track of mapped buffer usage static volatile int count; static volatile long totalSize; static volatile long totalCapacity; private volatile long address; private final long size; private final int cap; private final FileDescriptor fd; private Unmapper(long address, long size, int cap, FileDescriptor fd) { assert (address != 0); this.address = address; this.size = size; this.cap = cap; this.fd = fd; synchronized (Unmapper.class) { count++; totalSize += size; totalCapacity += cap; } } public void run() { if (address == 0) return; unmap0(address, size); address = 0; // if this mapping has a valid file descriptor then we close it if (fd.valid()) { try { nd.close(fd); } catch (IOException ignore) { // nothing we can do } } synchronized (Unmapper.class) { count--; totalSize -= size; totalCapacity -= cap; } } } //...... /** * Invoked by sun.management.ManagementFactoryHelper to create the management * interface for mapped buffers. */ public static JavaNioAccess.BufferPool getMappedBufferPool() { return new JavaNioAccess.BufferPool() { @Override public String getName() { return "mapped"; } @Override public long getCount() { return Unmapper.count; } @Override public long getTotalCapacity() { return Unmapper.totalCapacity; } @Override public long getMemoryUsed() { return Unmapper.totalSize; } }; } //...... }
FileChannelImpl定义了getMappedBufferPool方法,返回的是匿名JavaNioAccess.BufferPool,其相关返回实现直接使用Unmapper的对应方法;Unmapper实现了Runnable接口