提交 0c812b31 编写于 作者: A alanb

6682020: (bf) Support monitoring of direct and mapped buffer usage

Reviewed-by: mchung, iris
上级 d7586529
......@@ -449,6 +449,7 @@ JAVA_JAVA_java = \
sun/misc/JavaLangAccess.java \
sun/misc/JavaIOAccess.java \
sun/misc/JavaIODeleteOnExitAccess.java \
sun/misc/JavaIOFileDescriptorAccess.java
sun/misc/JavaIOFileDescriptorAccess.java \
sun/misc/JavaNioAccess.java
FILES_java = $(JAVA_JAVA_java)
......@@ -26,6 +26,7 @@
FILES_src = \
java/nio/Bits.java \
java/nio/Buffer.java \
java/nio/BufferPoolMXBean.java \
java/nio/ByteOrder.java \
java/nio/MappedByteBuffer.java \
java/nio/StringCharBuffer.java \
......
......@@ -32,6 +32,7 @@ import java.util.HashSet;
import java.util.Set;
import java.util.logging.LoggingMXBean;
import java.util.logging.LogManager;
import java.nio.BufferPoolMXBean;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
......@@ -188,6 +189,23 @@ enum PlatformComponent {
}
}),
/**
* Buffer pools.
*/
BUFFER_POOL(
"java.nio.BufferPoolMXBean",
"java.nio", "BufferPool", keyProperties("name"),
new MXBeanFetcher<BufferPoolMXBean>() {
public List<BufferPoolMXBean> getMXBeans() {
List<BufferPoolMXBean> pools = new ArrayList<BufferPoolMXBean>(2);
pools.add( sun.misc.SharedSecrets.getJavaNioAccess().getDirectBufferPoolMXBean() );
pools.add( sun.nio.ch.FileChannelImpl.getMappedBufferPoolMXBean() );
return pools;
}
}),
// Sun Platform Extension
/**
......
......@@ -29,6 +29,8 @@ import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.misc.Unsafe;
import sun.misc.VM;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
/**
* Access to bits, native and otherwise.
......@@ -625,13 +627,15 @@ class Bits { // package-private
// direct buffer memory. This value may be changed during VM
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
private static volatile long maxMemory = VM.maxDirectMemory();
private static volatile long reservedMemory = 0;
private static volatile long reservedMemory;
private static volatile long usedMemory;
private static volatile long count;
private static boolean memoryLimitSet = false;
// These methods should be called whenever direct memory is allocated or
// freed. They allow the user to control the amount of direct memory
// which a process may access. All sizes are specified in bytes.
static void reserveMemory(long size) {
static void reserveMemory(long size, int cap) {
synchronized (Bits.class) {
if (!memoryLimitSet && VM.isBooted()) {
......@@ -640,6 +644,8 @@ class Bits { // package-private
}
if (size <= maxMemory - reservedMemory) {
reservedMemory += size;
usedMemory += cap;
count++;
return;
}
}
......@@ -655,17 +661,71 @@ class Bits { // package-private
if (reservedMemory + size > maxMemory)
throw new OutOfMemoryError("Direct buffer memory");
reservedMemory += size;
usedMemory += cap;
count++;
}
}
static synchronized void unreserveMemory(long size) {
static synchronized void unreserveMemory(long size, int cap) {
if (reservedMemory > 0) {
reservedMemory -= size;
usedMemory -= cap;
count--;
assert (reservedMemory > -1);
}
}
// -- Management interface for monitoring of direct buffer usage --
static {
// setup access to this package in SharedSecrets
sun.misc.SharedSecrets.setJavaNioAccess(
new sun.misc.JavaNioAccess() {
@Override
public BufferPoolMXBean getDirectBufferPoolMXBean() {
return LazyInitialization.directBufferPoolMXBean;
}
}
);
}
// Lazy initialization of management interface
private static class LazyInitialization {
static final BufferPoolMXBean directBufferPoolMXBean = directBufferPoolMXBean();
private static BufferPoolMXBean directBufferPoolMXBean() {
final String pool = "direct";
final ObjectName obj;
try {
obj = new ObjectName("java.nio:type=BufferPool,name=" + pool);
} catch (MalformedObjectNameException x) {
throw new AssertionError(x);
}
return new BufferPoolMXBean() {
@Override
public ObjectName getObjectName() {
return obj;
}
@Override
public String getName() {
return pool;
}
@Override
public long getCount() {
return Bits.count;
}
@Override
public long getTotalCapacity() {
return Bits.usedMemory;
}
@Override
public long getMemoryUsed() {
return Bits.reservedMemory;
}
};
}
}
// -- Bulk get/put acceleration --
......
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package java.nio;
import java.lang.management.PlatformManagedObject;
/**
* The management interface for a buffer pool.
*
* <p> A class implementing this interface is an <a href=
* "java.lang.management.ManagementFactory.html#MXBean">MXBean</a>. A Java
* virtual machine has one or more implementations of this interface. The {@link
* java.lang.management.ManagementFactory#getPlatformMXBeans getPlatformMXBeans}
* method can be used to obtain the list of {@code BufferPoolMXBean} objects
* representing the management interfaces for pools of buffers as follows:
* <pre>
* List&lt;BufferPoolMXBean&gt; pools = ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
* </pre>
*
* <p> The management interfaces are also registered with the platform {@link
* javax.management.MBeanServer MBeanServer}. The {@link
* javax.management.ObjectName ObjectName} that uniquely identifies the
* management interface within the {@code MBeanServer} takes the form:
* <blockquote>
* <tt>java.nio:type=BufferPool</tt><tt>,name=</tt><i>pool name</i>
* </blockquote>
* where <em>pool name</em> is the {@link #getName name} of the buffer pool.
*
* @since 1.7
*/
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();
}
......@@ -71,11 +71,13 @@ class Direct$Type$Buffer$RW$$BO$
private static Unsafe unsafe = Unsafe.getUnsafe();
private long address;
private long size;
private int capacity;
private Deallocator(long address, int capacity) {
private Deallocator(long address, long size, int capacity) {
assert (address != 0);
this.address = address;
this.size = size;
this.capacity = capacity;
}
......@@ -86,7 +88,7 @@ class Direct$Type$Buffer$RW$$BO$
}
unsafe.freeMemory(address);
address = 0;
Bits.unreserveMemory(capacity);
Bits.unreserveMemory(size, capacity);
}
}
......@@ -110,23 +112,25 @@ class Direct$Type$Buffer$RW$$BO$
Direct$Type$Buffer$RW$(int cap) { // package-private
#if[rw]
super(-1, 0, cap, cap, false);
Bits.reserveMemory(cap);
int ps = Bits.pageSize();
int size = cap + ps;
Bits.reserveMemory(size, cap);
long base = 0;
try {
base = unsafe.allocateMemory(cap + ps);
base = unsafe.allocateMemory(size);
} catch (OutOfMemoryError x) {
Bits.unreserveMemory(cap);
Bits.unreserveMemory(size, cap);
throw x;
}
unsafe.setMemory(base, cap + ps, (byte) 0);
unsafe.setMemory(base, size, (byte) 0);
if (base % ps != 0) {
// Round up to page boundary
address = base + ps - (base & (ps - 1));
} else {
address = base;
}
cleaner = Cleaner.create(this, new Deallocator(base, cap));
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
#else[rw]
super(cap);
#end[rw]
......
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package sun.misc;
import java.nio.BufferPoolMXBean;
public interface JavaNioAccess {
BufferPoolMXBean getDirectBufferPoolMXBean();
}
......@@ -46,6 +46,7 @@ public class SharedSecrets {
private static JavaIOAccess javaIOAccess;
private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess;
private static JavaNetAccess javaNetAccess;
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
......@@ -77,6 +78,20 @@ public class SharedSecrets {
return javaNetAccess;
}
public static void setJavaNioAccess(JavaNioAccess jna) {
javaNioAccess = jna;
}
public static JavaNioAccess getJavaNioAccess() {
if (javaNioAccess == null) {
// Ensure java.nio.ByteOrder is initialized; we know that
// this class initializes java.nio.Bits that provides the
// shared secret.
unsafe.ensureClassInitialized(java.nio.ByteOrder.class);
}
return javaNioAccess;
}
public static void setJavaIOAccess(JavaIOAccess jia) {
javaIOAccess = jia;
}
......
......@@ -32,6 +32,7 @@ import java.io.RandomAccessFile;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.BufferPoolMXBean;
import java.nio.channels.*;
import java.nio.channels.spi.*;
import java.util.ArrayList;
......@@ -43,10 +44,12 @@ import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
import sun.misc.Cleaner;
import sun.security.action.GetPropertyAction;
public class FileChannelImpl
extends FileChannel
{
......@@ -681,14 +684,26 @@ public class FileChannelImpl
private static class Unmapper
implements Runnable
{
// keep track of mapped buffer usage
static volatile int count;
static volatile long totalSize;
static volatile long totalCapacity;
private long address;
private long size;
private int cap;
private Unmapper(long address, long size) {
private Unmapper(long address, long size, int cap) {
assert (address != 0);
this.address = address;
this.size = size;
this.cap = cap;
synchronized (Unmapper.class) {
count++;
totalSize += size;
totalCapacity += cap;
}
}
public void run() {
......@@ -696,8 +711,13 @@ public class FileChannelImpl
return;
unmap0(address, size);
address = 0;
}
synchronized (Unmapper.class) {
count--;
totalSize -= size;
totalCapacity -= cap;
}
}
}
private static void unmap(MappedByteBuffer bb) {
......@@ -786,7 +806,7 @@ public class FileChannelImpl
assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0);
int isize = (int)size;
Unmapper um = new Unmapper(addr, size + pagePosition);
Unmapper um = new Unmapper(addr, size + pagePosition, isize);
if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(isize, addr + pagePosition, um);
else
......@@ -797,6 +817,49 @@ public class FileChannelImpl
}
}
/**
* Returns the management interface for mapped buffers
*/
public static BufferPoolMXBean getMappedBufferPoolMXBean() {
return LazyInitialization.mappedBufferPoolMXBean;
}
// Lazy initialization of management interface
private static class LazyInitialization {
static final BufferPoolMXBean mappedBufferPoolMXBean = mappedBufferPoolMXBean();
private static BufferPoolMXBean mappedBufferPoolMXBean() {
final String pool = "mapped";
final ObjectName obj;
try {
obj = new ObjectName("java.nio:type=BufferPool,name=" + pool);
} catch (MalformedObjectNameException x) {
throw new AssertionError(x);
}
return new BufferPoolMXBean() {
@Override
public ObjectName getObjectName() {
return obj;
}
@Override
public String getName() {
return pool;
}
@Override
public long getCount() {
return Unmapper.count;
}
@Override
public long getTotalCapacity() {
return Unmapper.totalCapacity;
}
@Override
public long getMemoryUsed() {
return Unmapper.totalSize;
}
};
}
}
// -- Locks --
......
/*
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/* @test
* @bug 6606598
* @summary Unit test for java.nio.BufferPoolMXBean
*/
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.BufferPoolMXBean;
import java.nio.channels.FileChannel;
import java.io.File;
import java.io.RandomAccessFile;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.util.*;
public class Basic {
// static fields to ensure buffers aren't GC'ed
static List<ByteBuffer> buffers;
static MappedByteBuffer mbb;
// check counters
static void check(List<BufferPoolMXBean> pools,
int minBufferCount,
long minTotalCapacity)
{
int bufferCount = 0;
long totalCap = 0;
long totalMem = 0;
for (BufferPoolMXBean pool: pools) {
bufferCount += pool.getCount();
totalCap += pool.getTotalCapacity();
totalMem += pool.getMemoryUsed();
}
if (bufferCount < minBufferCount)
throw new RuntimeException("Count less than expected");
if (totalMem < minTotalCapacity)
throw new RuntimeException("Memory usage less than expected");
if (totalCap < minTotalCapacity)
throw new RuntimeException("Total capacity less than expected");
}
public static void main(String[] args) throws Exception {
Random rand = new Random();
// allocate a few direct buffers
int bufferCount = 5 + rand.nextInt(20);
buffers = new ArrayList<ByteBuffer>(bufferCount);
long totalCapacity = 0L;
for (int i=0; i<bufferCount; i++) {
int cap = 1024 + rand.nextInt(4096);
buffers.add( ByteBuffer.allocateDirect(cap) );
totalCapacity += cap;
}
// map a file
File f = File.createTempFile("blah", null);
f.deleteOnExit();
RandomAccessFile raf = new RandomAccessFile(f, "rw");
FileChannel fc = raf.getChannel();
mbb = fc.map(FileChannel.MapMode.READ_WRITE, 10, 100);
bufferCount++;
totalCapacity += mbb.capacity();
// direct
List<BufferPoolMXBean> pools =
ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class);
check(pools, bufferCount, totalCapacity);
// using MBeanServer
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
Set<ObjectName> mbeans = server.queryNames(
new ObjectName("java.nio:type=BufferPool,*"), null);
pools = new ArrayList<BufferPoolMXBean>();
for (ObjectName name: mbeans) {
BufferPoolMXBean pool = ManagementFactory
.newPlatformMXBeanProxy(server, name.toString(), BufferPoolMXBean.class);
pools.add(pool);
}
check(pools, bufferCount, totalCapacity);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册