Created
March 21, 2017 13:54
-
-
Save liuzhengyang/a0d25510d706c6f4c0805b367ad502da to your computer and use it in GitHub Desktop.
An Serviceability-Agent based tool to see stats of NIO direct memory for JDK8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.lang.reflect.*; | |
import java.lang.reflect.Method; | |
import java.util.*; | |
import sun.jvm.hotspot.memory.*; | |
import sun.jvm.hotspot.oops.*; | |
import sun.jvm.hotspot.debugger.*; | |
import sun.jvm.hotspot.runtime.*; | |
import sun.jvm.hotspot.tools.*; | |
import sun.jvm.hotspot.utilities.*; | |
public class DirectMemorySize extends Tool { | |
private boolean exactMallocMode; | |
private boolean verbose; | |
public DirectMemorySize(boolean exactMallocMode, boolean verbose) { | |
this.exactMallocMode = exactMallocMode; | |
this.verbose = verbose; | |
} | |
public void run() { | |
// Ready to go with the database... | |
try { | |
long reservedMemory = getStaticLongFieldValue("java.nio.Bits", "reservedMemory"); | |
long directMemory = getStaticLongFieldValue("sun.misc.VM", "directMemory"); | |
System.out.println("NIO direct memory: (in bytes)"); | |
System.out.printf(" reserved size = %f MB (%d bytes)\n", toM(reservedMemory), reservedMemory); | |
System.out.printf(" max size = %f MB (%d bytes)\n", toM(directMemory), directMemory); | |
if (verbose) { | |
System.out.println("Currently allocated direct buffers:"); | |
} | |
if (exactMallocMode || verbose) { | |
final long pageSize = getStaticIntFieldValue("java.nio.Bits", "pageSize"); | |
ObjectHeap heap = VM.getVM().getObjectHeap(); | |
InstanceKlass deallocatorKlass = | |
SystemDictionaryHelper.findInstanceKlass("java.nio.DirectByteBuffer$Deallocator"); | |
final LongField addressField = (LongField) deallocatorKlass.findField("address", "J"); | |
final IntField capacityField = (IntField) deallocatorKlass.findField("capacity", "I"); | |
final int[] countHolder = new int[1]; | |
heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { | |
public boolean doObj(Oop oop) { | |
long address = addressField.getValue(oop); | |
if (address == 0) return false; // this deallocator has already been run | |
long capacity = capacityField.getValue(oop); | |
long mallocSize = capacity + pageSize; | |
countHolder[0]++; | |
if (verbose) { | |
System.out.printf(" 0x%016x: capacity = %f MB (%d bytes)," | |
+ " mallocSize = %f MB (%d bytes)\n", | |
address, toM(capacity), capacity, | |
toM(mallocSize), mallocSize); | |
} | |
return false; | |
} | |
}, deallocatorKlass, false); | |
if (exactMallocMode) { | |
long totalMallocSize = reservedMemory + pageSize * countHolder[0]; | |
System.out.printf("NIO direct memory malloc'd size: %f MB (%d bytes)\n", | |
toM(totalMallocSize), totalMallocSize); | |
} | |
} | |
} catch (AddressException e) { | |
System.err.println("Error accessing address 0x" | |
+ Long.toHexString(e.getAddress())); | |
e.printStackTrace(); | |
} | |
} | |
public static long getStaticLongFieldValue(String className, String fieldName) { | |
InstanceKlass klass = SystemDictionaryHelper.findInstanceKlass(className); | |
LongField field = (LongField) klass.findField(fieldName, "J"); | |
return field.getValue(klass); // on JDK7 use: field.getValue(klass.getJavaMirror()); | |
} | |
public static int getStaticIntFieldValue(String className, String fieldName) { | |
InstanceKlass klass = SystemDictionaryHelper.findInstanceKlass(className); | |
IntField field = (IntField) klass.findField(fieldName, "I"); | |
return field.getValue(klass); // on JDK7 use: field.getValue(klass.getJavaMirror()); | |
} | |
public static double toM(long value) { | |
return value / (1024 * 1024.0); | |
} | |
public String getName() { | |
return "directMemorySize"; | |
} | |
protected void printFlagsUsage() { | |
System.out.println(" -e\tto print the actual size malloc'd"); | |
System.out.println(" -v\tto print verbose info of every live DirectByteBuffer allocated from Java"); | |
super.printFlagsUsage(); | |
} | |
public static void main(String[] args) { | |
boolean exactMallocMode = false; | |
boolean verbose = false; | |
// argument processing logic copied from sun.jvm.hotspot.tools.JStack | |
int used = 0; | |
for (String arg : args) { | |
if ("-e".equals(arg)) { | |
exactMallocMode = true; | |
used++; | |
} else if ("-v".equals(arg)) { | |
verbose = true; | |
used++; | |
} | |
} | |
if (used != 0) { | |
args = Arrays.copyOfRange(args, used, args.length); | |
} | |
DirectMemorySize tool = new DirectMemorySize(exactMallocMode, verbose); | |
try { | |
Method start = Tool.class.getDeclaredMethod("start", Class.forName("[Ljava.lang.String;")); | |
start.setAccessible(true); | |
start.invoke(tool, new Object[]{args}); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
tool.stop(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Caused by: java.lang.NullPointerException
at DirectMemorySize.getStaticLongFieldValue(DirectMemorySize.java:79)