InMemProfiler is a tool for tracking the allocation and lifetime of Java objects.
Download (see below for how to use these files):
Latest release made on 27/01/2012. See Release Notes for details.
Java makes it really easy to write code which allocates a lot of short lived memory (e.g. String concatenation) or to use memory structures which are larger than you might expect (e.g. Vectors).
This tool aims to answer the following questions.
Here is some example output from the tool.
Live objects: 56:1 - [Ljava.lang.Object; 24:1 - java.util.ArrayList Live objects summary: 80:2 Collected objects: 0(s) - 5(s) : 440:6 - [Ljava.lang.Object; 24:1 - java.util.ArrayList 8:1 - other.test.TestObject 5(s) - 15(s) : 80:10 - other.test.TestObject 56:1 - [Ljava.lang.Object; 24:1 - java.util.ArrayList 15(s) - 25(s) : 160:20 - other.test.TestObject 112:1 - [Ljava.lang.Object; 24:1 - java.util.ArrayList 25(s) - 35(s) : 240:30 - other.test.TestObject 168:1 - [Ljava.lang.Object; 24:1 - java.util.ArrayList 35(s) - 45(s) : 45(s) - 55(s) : 55(s) - inf(s) : Buckets summary: 472:8 - 0(s) - 5(s) 160:12 - 5(s) - 15(s) 296:22 - 15(s) - 25(s) 432:32 - 25(s) - 35(s) 0:0 - 35(s) - 45(s) 0:0 - 45(s) - 55(s) 0:0 - 55(s) - inf(s)
This output is generated from the following test program:
package test; import java.util.ArrayList; import java.util.List; import other.test.TestObject; public class Test { public static void main(String[] args) throws Exception { // Allocate 30 objects Listround1 = allocateObjects(30); Thread.sleep(10 * 1000); // Allocate 20 objects List round2 = allocateObjects(20); Thread.sleep(10 * 1000); // Allocate 10 objects List round3 = allocateObjects(10); Thread.sleep(10 * 1000); // Allocate 1 object, discarding 30 which are 30 seconds old round1 = allocateObjects(1); System.out.println(round1); // Discard 1 object which is 0 seconds old round1 = null; System.out.println(round2); // Discard 20 objects which are 20 seconds old round2 = null; System.out.println(round3); // Discard 30 objects which are 30 seconds old round3 = null; Thread.sleep(6 * 1000); System.out.println("==="); } private static List allocateObjects(int len) { List list = new ArrayList (); for (int ii = 0; ii < len; ii++) { list.add(new TestObject()); } return list; } }
Note: The extra ArrayList instance alive at the end of this code is created by a JVM system class. This will become clearer below.
This output is made possible by adding the following arguments to the JVM used to run this program.
-Xbootclasspath/a:./inmemprofiler.jar -agentpath:./inmemprofiler.dll=#bucket-5,15,25,35,45,55#gc-1#include-other,[Ljava.lang.Object,java.util.ArrayList#trackcollection
To find out more about the source of these objects you can use the #trace option to generate the following output:
Live objects: 56:1 - [Ljava.lang.Object; Allocation Sites: 56:1 java.util.ArrayList.`(ArrayList.java) java.util.ArrayList. (ArrayList.java) java.io.FilePermissionCollection. (FilePermission.java) java.io.FilePermission.newPermissionCollection(FilePermission.java) java.security.Permissions.getPermissionCollection(Permissions.java) java.security.Permissions.add(Permissions.java) java.net.URLClassLoader.getPermissions(URLClassLoader.java) sun.misc.Launcher$AppClassLoader.getPermissions(Launcher.java) java.security.SecureClassLoader.getProtectionDomain(SecureClassLoader.java) java.security.SecureClassLoader.defineClass(SecureClassLoader.java) java.net.URLClassLoader.defineClass(URLClassLoader.java) java.net.URLClassLoader.access$000(URLClassLoader.java) java.net.URLClassLoader$1.run(URLClassLoader.java) java.security.AccessController.doPrivileged(AccessController.java) java.net.URLClassLoader.findClass(URLClassLoader.java) java.lang.ClassLoader.loadClass(ClassLoader.java) sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java) java.lang.ClassLoader.loadClass(ClassLoader.java) Allocation Classes: java.security.Permissions 56:1 - All methods 56:1 - add 56:1 - getPermissionCollection java.security.SecureClassLoader 56:1 - All methods 56:1 - getProtectionDomain 56:1 - defineClass sun.misc.Launcher$AppClassLoader 56:1 - All methods 56:1 - loadClass 56:1 - getPermissions java.io.FilePermission 56:1 - All methods 56:1 - newPermissionCollection java.lang.ClassLoader 56:1 - All methods 56:1 - loadClass java.net.URLClassLoader 56:1 - All methods 56:1 - access$000 56:1 - findClass 56:1 - defineClass 56:1 - getPermissions java.util.ArrayList 56:1 - All methods 56:1 - 0:0 - add 0:0 - ensureCapacity java.security.AccessController 56:1 - All methods 56:1 - doPrivileged java.net.URLClassLoader$1 56:1 - All methods 56:1 - run java.io.FilePermissionCollection 56:1 - All methods 56:1 - 24:1 - java.util.ArrayList Allocation Sites: 24:1 java.util.ArrayList. (ArrayList.java) java.io.FilePermissionCollection. (FilePermission.java) java.io.FilePermission.newPermissionCollection(FilePermission.java) java.security.Permissions.getPermissionCollection(Permissions.java) java.security.Permissions.add(Permissions.java) java.net.URLClassLoader.getPermissions(URLClassLoader.java) sun.misc.Launcher$AppClassLoader.getPermissions(Launcher.java) java.security.SecureClassLoader.getProtectionDomain(SecureClassLoader.java) java.security.SecureClassLoader.defineClass(SecureClassLoader.java) java.net.URLClassLoader.defineClass(URLClassLoader.java) java.net.URLClassLoader.access$000(URLClassLoader.java) java.net.URLClassLoader$1.run(URLClassLoader.java) java.security.AccessController.doPrivileged(AccessController.java) java.net.URLClassLoader.findClass(URLClassLoader.java) java.lang.ClassLoader.loadClass(ClassLoader.java) sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java) java.lang.ClassLoader.loadClass(ClassLoader.java) Allocation Classes: java.security.Permissions 24:1 - All methods 24:1 - add 24:1 - getPermissionCollection java.security.SecureClassLoader 24:1 - All methods 24:1 - getProtectionDomain 24:1 - defineClass sun.misc.Launcher$AppClassLoader 24:1 - All methods 24:1 - loadClass 24:1 - getPermissions java.io.FilePermission 24:1 - All methods 24:1 - newPermissionCollection java.lang.ClassLoader 24:1 - All methods 24:1 - loadClass java.net.URLClassLoader 24:1 - All methods 24:1 - access$000 24:1 - findClass 24:1 - defineClass 24:1 - getPermissions java.util.ArrayList 24:1 - All methods 24:1 - java.security.AccessController 24:1 - All methods 24:1 - doPrivileged java.net.URLClassLoader$1 24:1 - All methods 24:1 - run java.io.FilePermissionCollection 24:1 - All methods 24:1 - Live objects summary: 80:2 Collected objects: 0(s) - 60(s) : 776:9 - [Ljava.lang.Object; Allocation Sites: 552:5 java.util.Arrays.copyOf(Arrays.java) java.util.Arrays.copyOf(Arrays.java) java.util.ArrayList.ensureCapacity(ArrayList.java) java.util.ArrayList.add(ArrayList.java) test.Test.allocateObjects(Test.java) test.Test.main(Test.java) 224:4 java.util.ArrayList. (ArrayList.java) java.util.ArrayList. (ArrayList.java) test.Test.allocateObjects(Test.java) test.Test.main(Test.java) Allocation Classes: java.util.ArrayList 776:9 - All methods 552:5 - add 552:5 - ensureCapacity 224:4 - test.Test 776:9 - All methods 776:9 - allocateObjects 776:9 - main java.util.Arrays 552:5 - All methods 552:5 - copyOf 488:61 - other.test.TestObject Allocation Sites: 488:61 test.Test.allocateObjects(Test.java) test.Test.main(Test.java) Allocation Classes: test.Test 488:61 - All methods 488:61 - allocateObjects 488:61 - main 96:4 - java.util.ArrayList Allocation Sites: 96:4 java.util.ArrayList. (ArrayList.java) test.Test.allocateObjects(Test.java) test.Test.main(Test.java) Allocation Classes: java.util.ArrayList 96:4 - All methods 96:4 - test.Test 96:4 - All methods 96:4 - allocateObjects 96:4 - main 60(s) - inf(s) : Buckets summary: 1360:74 - 0(s) - 60(s) 0:0 - 60(s) - inf(s)
This was generated with the following set of options:
-Xbootclasspath/a:./inmemprofiler.jar -agentpath:./inmemprofiler.dll=#bucket-60#gc-1#include-other,[Ljava.lang.Object,java.util.ArrayList#trackcollection#trace
This output clearly shows that the extra ArrayList instance and corresponding Object[] comes from a call to URLClassLoader.getPermissions during classloading.
To use this tool you should download the following two files (select the appropriate dll or so file) into your application�s working directory:
You then need to add the following arguments to your java command.
-Xbootclasspath/a:./inmemprofiler.jar -agentpath:./inmemprofiler.dll
-Xbootclasspath/a:./inmemprofiler.jar -agentpath:./libinmemprofiler.so
You can specify arguments to the agent in string form e.g.
-Xbootclasspath/a:./inmemprofiler.jar -agentpath:./inmemprofiler.dll=#bucket-5,15,25,35,45,55#include-other,java.util.ArrayList#gc-1
The full list of options is described on the Profiler Options page.