提交 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 = \ ...@@ -449,6 +449,7 @@ JAVA_JAVA_java = \
sun/misc/JavaLangAccess.java \ sun/misc/JavaLangAccess.java \
sun/misc/JavaIOAccess.java \ sun/misc/JavaIOAccess.java \
sun/misc/JavaIODeleteOnExitAccess.java \ sun/misc/JavaIODeleteOnExitAccess.java \
sun/misc/JavaIOFileDescriptorAccess.java sun/misc/JavaIOFileDescriptorAccess.java \
sun/misc/JavaNioAccess.java
FILES_java = $(JAVA_JAVA_java) FILES_java = $(JAVA_JAVA_java)
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
FILES_src = \ FILES_src = \
java/nio/Bits.java \ java/nio/Bits.java \
java/nio/Buffer.java \ java/nio/Buffer.java \
java/nio/BufferPoolMXBean.java \
java/nio/ByteOrder.java \ java/nio/ByteOrder.java \
java/nio/MappedByteBuffer.java \ java/nio/MappedByteBuffer.java \
java/nio/StringCharBuffer.java \ java/nio/StringCharBuffer.java \
......
...@@ -32,6 +32,7 @@ import java.util.HashSet; ...@@ -32,6 +32,7 @@ import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.logging.LoggingMXBean; import java.util.logging.LoggingMXBean;
import java.util.logging.LogManager; import java.util.logging.LogManager;
import java.nio.BufferPoolMXBean;
import javax.management.MBeanServerConnection; import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException; import javax.management.MalformedObjectNameException;
import javax.management.ObjectName; import javax.management.ObjectName;
...@@ -188,6 +189,23 @@ enum PlatformComponent { ...@@ -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 // Sun Platform Extension
/** /**
......
...@@ -29,6 +29,8 @@ import java.security.AccessController; ...@@ -29,6 +29,8 @@ import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import sun.misc.Unsafe; import sun.misc.Unsafe;
import sun.misc.VM; import sun.misc.VM;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
/** /**
* Access to bits, native and otherwise. * Access to bits, native and otherwise.
...@@ -625,13 +627,15 @@ class Bits { // package-private ...@@ -625,13 +627,15 @@ class Bits { // package-private
// direct buffer memory. This value may be changed during VM // direct buffer memory. This value may be changed during VM
// initialization if it is launched with "-XX:MaxDirectMemorySize=<size>". // initialization if it is launched with "-XX:MaxDirectMemorySize=<size>".
private static volatile long maxMemory = VM.maxDirectMemory(); 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; private static boolean memoryLimitSet = false;
// These methods should be called whenever direct memory is allocated or // These methods should be called whenever direct memory is allocated or
// freed. They allow the user to control the amount of direct memory // freed. They allow the user to control the amount of direct memory
// which a process may access. All sizes are specified in bytes. // 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) { synchronized (Bits.class) {
if (!memoryLimitSet && VM.isBooted()) { if (!memoryLimitSet && VM.isBooted()) {
...@@ -640,6 +644,8 @@ class Bits { // package-private ...@@ -640,6 +644,8 @@ class Bits { // package-private
} }
if (size <= maxMemory - reservedMemory) { if (size <= maxMemory - reservedMemory) {
reservedMemory += size; reservedMemory += size;
usedMemory += cap;
count++;
return; return;
} }
} }
...@@ -655,17 +661,71 @@ class Bits { // package-private ...@@ -655,17 +661,71 @@ class Bits { // package-private
if (reservedMemory + size > maxMemory) if (reservedMemory + size > maxMemory)
throw new OutOfMemoryError("Direct buffer memory"); throw new OutOfMemoryError("Direct buffer memory");
reservedMemory += size; reservedMemory += size;
usedMemory += cap;
count++;
} }
} }
static synchronized void unreserveMemory(long size) { static synchronized void unreserveMemory(long size, int cap) {
if (reservedMemory > 0) { if (reservedMemory > 0) {
reservedMemory -= size; reservedMemory -= size;
usedMemory -= cap;
count--;
assert (reservedMemory > -1); 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 -- // -- 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$ ...@@ -71,11 +71,13 @@ class Direct$Type$Buffer$RW$$BO$
private static Unsafe unsafe = Unsafe.getUnsafe(); private static Unsafe unsafe = Unsafe.getUnsafe();
private long address; private long address;
private long size;
private int capacity; private int capacity;
private Deallocator(long address, int capacity) { private Deallocator(long address, long size, int capacity) {
assert (address != 0); assert (address != 0);
this.address = address; this.address = address;
this.size = size;
this.capacity = capacity; this.capacity = capacity;
} }
...@@ -86,7 +88,7 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -86,7 +88,7 @@ class Direct$Type$Buffer$RW$$BO$
} }
unsafe.freeMemory(address); unsafe.freeMemory(address);
address = 0; address = 0;
Bits.unreserveMemory(capacity); Bits.unreserveMemory(size, capacity);
} }
} }
...@@ -110,23 +112,25 @@ class Direct$Type$Buffer$RW$$BO$ ...@@ -110,23 +112,25 @@ class Direct$Type$Buffer$RW$$BO$
Direct$Type$Buffer$RW$(int cap) { // package-private Direct$Type$Buffer$RW$(int cap) { // package-private
#if[rw] #if[rw]
super(-1, 0, cap, cap, false); super(-1, 0, cap, cap, false);
Bits.reserveMemory(cap);
int ps = Bits.pageSize(); int ps = Bits.pageSize();
int size = cap + ps;
Bits.reserveMemory(size, cap);
long base = 0; long base = 0;
try { try {
base = unsafe.allocateMemory(cap + ps); base = unsafe.allocateMemory(size);
} catch (OutOfMemoryError x) { } catch (OutOfMemoryError x) {
Bits.unreserveMemory(cap); Bits.unreserveMemory(size, cap);
throw x; throw x;
} }
unsafe.setMemory(base, cap + ps, (byte) 0); unsafe.setMemory(base, size, (byte) 0);
if (base % ps != 0) { if (base % ps != 0) {
// Round up to page boundary // Round up to page boundary
address = base + ps - (base & (ps - 1)); address = base + ps - (base & (ps - 1));
} else { } else {
address = base; address = base;
} }
cleaner = Cleaner.create(this, new Deallocator(base, cap)); cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
#else[rw] #else[rw]
super(cap); super(cap);
#end[rw] #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 { ...@@ -46,6 +46,7 @@ public class SharedSecrets {
private static JavaIOAccess javaIOAccess; private static JavaIOAccess javaIOAccess;
private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess; private static JavaIODeleteOnExitAccess javaIODeleteOnExitAccess;
private static JavaNetAccess javaNetAccess; private static JavaNetAccess javaNetAccess;
private static JavaNioAccess javaNioAccess;
private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess; private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
public static JavaUtilJarAccess javaUtilJarAccess() { public static JavaUtilJarAccess javaUtilJarAccess() {
...@@ -77,6 +78,20 @@ public class SharedSecrets { ...@@ -77,6 +78,20 @@ public class SharedSecrets {
return javaNetAccess; 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) { public static void setJavaIOAccess(JavaIOAccess jia) {
javaIOAccess = jia; javaIOAccess = jia;
} }
......
...@@ -32,6 +32,7 @@ import java.io.RandomAccessFile; ...@@ -32,6 +32,7 @@ import java.io.RandomAccessFile;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer; import java.nio.MappedByteBuffer;
import java.nio.BufferPoolMXBean;
import java.nio.channels.*; import java.nio.channels.*;
import java.nio.channels.spi.*; import java.nio.channels.spi.*;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -43,10 +44,12 @@ import java.lang.ref.ReferenceQueue; ...@@ -43,10 +44,12 @@ import java.lang.ref.ReferenceQueue;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import javax.management.ObjectName;
import javax.management.MalformedObjectNameException;
import sun.misc.Cleaner; import sun.misc.Cleaner;
import sun.security.action.GetPropertyAction; import sun.security.action.GetPropertyAction;
public class FileChannelImpl public class FileChannelImpl
extends FileChannel extends FileChannel
{ {
...@@ -681,14 +684,26 @@ public class FileChannelImpl ...@@ -681,14 +684,26 @@ public class FileChannelImpl
private static class Unmapper private static class Unmapper
implements Runnable 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 address;
private long size; private long size;
private int cap;
private Unmapper(long address, long size) { private Unmapper(long address, long size, int cap) {
assert (address != 0); assert (address != 0);
this.address = address; this.address = address;
this.size = size; this.size = size;
this.cap = cap;
synchronized (Unmapper.class) {
count++;
totalSize += size;
totalCapacity += cap;
}
} }
public void run() { public void run() {
...@@ -696,8 +711,13 @@ public class FileChannelImpl ...@@ -696,8 +711,13 @@ public class FileChannelImpl
return; return;
unmap0(address, size); unmap0(address, size);
address = 0; address = 0;
}
synchronized (Unmapper.class) {
count--;
totalSize -= size;
totalCapacity -= cap;
}
}
} }
private static void unmap(MappedByteBuffer bb) { private static void unmap(MappedByteBuffer bb) {
...@@ -786,7 +806,7 @@ public class FileChannelImpl ...@@ -786,7 +806,7 @@ public class FileChannelImpl
assert (IOStatus.checkAll(addr)); assert (IOStatus.checkAll(addr));
assert (addr % allocationGranularity == 0); assert (addr % allocationGranularity == 0);
int isize = (int)size; int isize = (int)size;
Unmapper um = new Unmapper(addr, size + pagePosition); Unmapper um = new Unmapper(addr, size + pagePosition, isize);
if ((!writable) || (imode == MAP_RO)) if ((!writable) || (imode == MAP_RO))
return Util.newMappedByteBufferR(isize, addr + pagePosition, um); return Util.newMappedByteBufferR(isize, addr + pagePosition, um);
else else
...@@ -797,6 +817,49 @@ public class FileChannelImpl ...@@ -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 -- // -- 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.
先完成此消息的编辑!
想要评论请 注册