Also works on core dumps, in the form of:
java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize $JAVA_HOME/bin/java core.xxx
| $ java -version | |
| java version "1.6.0_30" | |
| Java(TM) SE Runtime Environment (build 1.6.0_30-b12) | |
| Java HotSpot(TM) 64-Bit Server VM (build 20.5-b03, mixed mode) | |
| $ javac -classpath $JAVA_HOME/lib/sa-jdi.jar DirectMemorySize.java | |
| $ jps | |
| 18486 GroovyStarter | |
| 23135 Jps | |
| $ java -classpath .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize `pgrep java` | |
| Attaching to process ID 18486, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000000 MB (0 bytes) | |
| max size = 4069.000000 MB (4266655744 bytes) |
| [sajia@211 temp]$ java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize | |
| Usage: java directMemorySize [option] <pid> | |
| (to connect to a live java process) | |
| or java directMemorySize [option] <executable> <core> | |
| (to connect to a core file) | |
| or java directMemorySize [option] [server_id@]<remote server IP or hostname> | |
| (to connect to a remote debug server) | |
| where option must be one of: | |
| -e to print the actual size malloc'd | |
| -v to print verbose info of every live DirectByteBuffer allocated from Java | |
| -h | -help to print this help message | |
| [sajia@211 temp]$ java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize `pgrep -u sajia java` | |
| Attaching to process ID 7381, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000003 MB (3 bytes) | |
| max size = 7152.000000 MB (7499415552 bytes) | |
| [sajia@211 temp]$ java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize -e `pgrep -u sajia java` | |
| Attaching to process ID 7381, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000003 MB (3 bytes) | |
| max size = 7152.000000 MB (7499415552 bytes) | |
| Finding object size using Printezis bits and skipping over... | |
| Finding object size using Printezis bits and skipping over... | |
| NIO direct memory malloc'd size: 0.007815 MB (8195 bytes) | |
| [sajia@211 temp]$ time java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize `pgrep -u sajia java` | |
| Attaching to process ID 7381, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000003 MB (3 bytes) | |
| max size = 7152.000000 MB (7499415552 bytes) | |
| real 0m0.401s | |
| user 0m0.503s | |
| sys 0m0.057s | |
| [sajia@211 temp]$ time java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize -e `pgrep -u sajia java` | |
| Attaching to process ID 7381, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000003 MB (3 bytes) | |
| max size = 7152.000000 MB (7499415552 bytes) | |
| Finding object size using Printezis bits and skipping over... | |
| Finding object size using Printezis bits and skipping over... | |
| NIO direct memory malloc'd size: 0.007815 MB (8195 bytes) | |
| real 0m4.822s | |
| user 0m2.095s | |
| sys 0m3.216s | |
| [sajia@211 temp]$ time java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize -e -v `pgrep -u sajia java` | |
| Attaching to process ID 7381, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.5-b03 | |
| NIO direct memory: (in bytes) | |
| reserved size = 0.000003 MB (3 bytes) | |
| max size = 7152.000000 MB (7499415552 bytes) | |
| Currently allocated direct buffers: | |
| 0x00002aaab021df10: capacity = 0.000001 MB (1 bytes), mallocSize = 0.003907 MB (4097 bytes) | |
| 0x00002aaab0843310: capacity = 0.000002 MB (2 bytes), mallocSize = 0.003908 MB (4098 bytes) | |
| Finding object size using Printezis bits and skipping over... | |
| Finding object size using Printezis bits and skipping over... | |
| NIO direct memory malloc'd size: 0.007815 MB (8195 bytes) | |
| real 0m5.097s | |
| user 0m2.164s | |
| sys 0m3.426s | |
| [sajia@211 temp]$ |
| [sajia@xxx164 gist]$ sudo -u admin java -cp .:$JAVA_HOME/lib/sa-jdi.jar DirectMemorySize -e `pgrep -u admin java` | grep -v 'Finding object' | |
| Attaching to process ID 2499, please wait... | |
| Debugger attached successfully. | |
| Server compiler detected. | |
| JVM version is 20.0-b12-internal | |
| NIO direct memory: (in bytes) | |
| reserved size = 907.541405 MB (951626136 bytes) | |
| max size = 3925.375000 MB (4116054016 bytes) | |
| NIO direct memory malloc'd size: 910.697655 MB (954935704 bytes) |
| import java.io.*; | |
| 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); | |
| tool.start(args); | |
| tool.stop(); | |
| } | |
| } |