43 */
44 public class JMap {
45
46 // Options handled by the attach mechanism
47 private static String HISTO_OPTION = "-histo";
48 private static String LIVE_HISTO_OPTION = "-histo:live";
49 private static String DUMP_OPTION_PREFIX = "-dump:";
50
51 // These options imply the use of a SA tool
52 private static String SA_TOOL_OPTIONS =
53 "-heap|-heap:format=b|-clstats|-finalizerinfo";
54
55 // The -F (force) option is currently not passed through to SA
56 private static String FORCE_SA_OPTION = "-F";
57
58 // Default option (if nothing provided)
59 private static String DEFAULT_OPTION = "-pmap";
60
61 public static void main(String[] args) throws Exception {
62 if (args.length == 0) {
63 usage(); // no arguments
64 }
65
66 // used to indicate if we should use SA
67 boolean useSA = false;
68
69 // the chosen option (-heap, -dump:*, ... )
70 String option = null;
71
72 // First iterate over the options (arguments starting with -). There should be
73 // one (but maybe two if -F is also used).
74 int optionCount = 0;
75 while (optionCount < args.length) {
76 String arg = args[optionCount];
77 if (!arg.startsWith("-")) {
78 break;
79 }
80 if (arg.equals(FORCE_SA_OPTION)) {
81 useSA = true;
82 } else {
83 if (option != null) {
84 usage(); // option already specified
85 }
86 option = arg;
87 }
88 optionCount++;
89 }
90
91 // if no option provided then use default.
92 if (option == null) {
93 option = DEFAULT_OPTION;
94 }
95 if (option.matches(SA_TOOL_OPTIONS)) {
96 useSA = true;
97 }
98
99 // Next we check the parameter count. For the SA tools there are
100 // one or two parameters. For the built-in -dump option there is
101 // only one parameter (the process-id)
102 int paramCount = args.length - optionCount;
103 if (paramCount == 0 || paramCount > 2) {
104 usage();
105 }
106
107 if (optionCount == 0 || paramCount != 1) {
108 useSA = true;
109 } else {
110 // the parameter for the -dump option is a process-id.
111 // If it doesn't parse to a number then it must be SA
112 // debug server
113 if (!args[optionCount].matches("[0-9]+")) {
114 useSA = true;
115 }
116 }
117
118
119 // at this point we know if we are executing an SA tool or a built-in
120 // option.
121
122 if (useSA) {
123 // parameters (<pid> or <exe> <core>)
124 String params[] = new String[paramCount];
125 for (int i=optionCount; i<args.length; i++ ){
126 params[i-optionCount] = args[i];
127 }
128 runTool(option, params);
129
130 } else {
131 String pid = args[1];
132 // Here we handle the built-in options
133 // As more options are added we should create an abstract tool class and
134 // have a table to map the options
135 if (option.equals(HISTO_OPTION)) {
136 histo(pid, false);
137 } else if (option.equals(LIVE_HISTO_OPTION)) {
138 histo(pid, true);
139 } else if (option.startsWith(DUMP_OPTION_PREFIX)) {
140 dump(pid, option);
141 } else {
142 usage();
143 }
144 }
145 }
146
147 // Invoke SA tool with the given arguments
148 private static void runTool(String option, String args[]) throws Exception {
149 String[][] tools = {
150 { "-pmap", "sun.jvm.hotspot.tools.PMap" },
151 { "-heap", "sun.jvm.hotspot.tools.HeapSummary" },
152 { "-heap:format=b", "sun.jvm.hotspot.tools.HeapDumper" },
153 { "-histo", "sun.jvm.hotspot.tools.ObjectHistogram" },
154 { "-clstats", "sun.jvm.hotspot.tools.ClassLoaderStats" },
155 { "-finalizerinfo", "sun.jvm.hotspot.tools.FinalizerInfo" },
156 };
157
158 String tool = null;
159
160 // -dump option needs to be handled in a special way
161 if (option.startsWith(DUMP_OPTION_PREFIX)) {
162 // first check that the option can be parsed
163 String fn = parseDumpOptions(option);
164 if (fn == null) usage();
165
166 // tool for heap dumping
167 tool = "sun.jvm.hotspot.tools.HeapDumper";
168
169 // HeapDumper -f <file>
170 args = prepend(fn, args);
171 args = prepend("-f", args);
172 } else {
173 int i=0;
174 while (i < tools.length) {
175 if (option.equals(tools[i][0])) {
176 tool = tools[i][1];
177 break;
178 }
179 i++;
180 }
181 }
182 if (tool == null) {
183 usage(); // no mapping to tool
184 }
185
186 // Tool not available on this platform.
187 Class<?> c = loadClass(tool);
188 if (c == null) {
189 usage();
190 }
191
192 // invoke the main method with the arguments
193 Class[] argTypes = { String[].class } ;
194 Method m = c.getDeclaredMethod("main", argTypes);
195
196 Object[] invokeArgs = { args };
197 m.invoke(null, invokeArgs);
198 }
199
200 // loads the given class using the system class loader
201 private static Class<?> loadClass(String name) {
202 //
203 // We specify the system clas loader so as to cater for development
204 // environments where this class is on the boot class path but sa-jdi.jar
205 // is on the system class path. Once the JDK is deployed then both
206 // tools.jar and sa-jdi.jar are on the system class path.
207 //
208 try {
209 return Class.forName(name, true,
210 ClassLoader.getSystemClassLoader());
211 } catch (Exception x) { }
212 return null;
213 }
214
215 private static final String LIVE_OBJECTS_OPTION = "-live";
216 private static final String ALL_OBJECTS_OPTION = "-all";
217 private static void histo(String pid, boolean live) throws IOException {
218 VirtualMachine vm = attach(pid);
219 InputStream in = ((HotSpotVirtualMachine)vm).
220 heapHisto(live ? LIVE_OBJECTS_OPTION : ALL_OBJECTS_OPTION);
221 drain(vm, in);
222 }
223
224 private static void dump(String pid, String options) throws IOException {
225 // parse the options to get the dump filename
226 String filename = parseDumpOptions(options);
227 if (filename == null) {
228 usage(); // invalid options or no filename
229 }
230
231 // get the canonical path - important to avoid just passing
232 // a "heap.bin" and having the dump created in the target VM
233 // working directory rather than the directory where jmap
234 // is executed.
235 filename = new File(filename).getCanonicalPath();
236
237 // dump live objects only or not
238 boolean live = isDumpLiveObjects(options);
239
240 VirtualMachine vm = attach(pid);
241 System.out.println("Dumping heap to " + filename + " ...");
242 InputStream in = ((HotSpotVirtualMachine)vm).
243 dumpHeap((Object)filename,
244 (live ? LIVE_OBJECTS_OPTION : ALL_OBJECTS_OPTION));
245 drain(vm, in);
246 }
247
248 // Parse the options to the -dump option. Valid options are format=b and
324 } while (n > 0);
325 in.close();
326 vm.detach();
327 }
328
329 // return a new string array with arg as the first element
330 private static String[] prepend(String arg, String args[]) {
331 String[] newargs = new String[args.length+1];
332 newargs[0] = arg;
333 System.arraycopy(args, 0, newargs, 1, args.length);
334 return newargs;
335 }
336
337 // returns true if SA is available
338 private static boolean haveSA() {
339 Class<?> c = loadClass("sun.jvm.hotspot.tools.HeapSummary");
340 return (c != null);
341 }
342
343 // print usage message
344 private static void usage() {
345 System.out.println("Usage:");
346 if (haveSA()) {
347 System.out.println(" jmap [option] <pid>");
348 System.out.println(" (to connect to running process)");
349 System.out.println(" jmap [option] <executable <core>");
350 System.out.println(" (to connect to a core file)");
351 System.out.println(" jmap [option] [server_id@]<remote server IP or hostname>");
352 System.out.println(" (to connect to remote debug server)");
353 System.out.println("");
354 System.out.println("where <option> is one of:");
355 System.out.println(" <none> to print same info as Solaris pmap");
356 System.out.println(" -heap to print java heap summary");
357 System.out.println(" -histo[:live] to print histogram of java object heap; if the \"live\"");
358 System.out.println(" suboption is specified, only count live objects");
359 System.out.println(" -clstats to print class loader statistics");
360 System.out.println(" -finalizerinfo to print information on objects awaiting finalization");
361 System.out.println(" -dump:<dump-options> to dump java heap in hprof binary format");
362 System.out.println(" dump-options:");
363 System.out.println(" live dump only live objects; if not specified,");
364 System.out.println(" all objects in the heap are dumped.");
365 System.out.println(" format=b binary format");
366 System.out.println(" file=<file> dump heap to <file>");
367 System.out.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
368 System.out.println(" -F force. Use with -dump:<dump-options> <pid> or -histo");
369 System.out.println(" to force a heap dump or histogram when <pid> does not");
370 System.out.println(" respond. The \"live\" suboption is not supported");
371 System.out.println(" in this mode.");
372 System.out.println(" -h | -help to print this help message");
373 System.out.println(" -J<flag> to pass <flag> directly to the runtime system");
374 } else {
375 System.out.println(" jmap -histo <pid>");
376 System.out.println(" (to connect to running process and print histogram of java object heap");
377 System.out.println(" jmap -dump:<dump-options> <pid>");
378 System.out.println(" (to connect to running process and dump java heap)");
379 System.out.println("");
380 System.out.println(" dump-options:");
381 System.out.println(" format=b binary default");
382 System.out.println(" file=<file> dump heap to <file>");
383 System.out.println("");
384 System.out.println(" Example: jmap -dump:format=b,file=heap.bin <pid>");
385 }
386
387 System.exit(1);
388 }
389 }
|
43 */
44 public class JMap {
45
46 // Options handled by the attach mechanism
47 private static String HISTO_OPTION = "-histo";
48 private static String LIVE_HISTO_OPTION = "-histo:live";
49 private static String DUMP_OPTION_PREFIX = "-dump:";
50
51 // These options imply the use of a SA tool
52 private static String SA_TOOL_OPTIONS =
53 "-heap|-heap:format=b|-clstats|-finalizerinfo";
54
55 // The -F (force) option is currently not passed through to SA
56 private static String FORCE_SA_OPTION = "-F";
57
58 // Default option (if nothing provided)
59 private static String DEFAULT_OPTION = "-pmap";
60
61 public static void main(String[] args) throws Exception {
62 if (args.length == 0) {
63 usage(1); // no arguments
64 }
65
66 // used to indicate if we should use SA
67 boolean useSA = false;
68
69 // the chosen option (-heap, -dump:*, ... )
70 String option = null;
71
72 // First iterate over the options (arguments starting with -). There should be
73 // one (but maybe two if -F is also used).
74 int optionCount = 0;
75 while (optionCount < args.length) {
76 String arg = args[optionCount];
77 if (!arg.startsWith("-")) {
78 break;
79 }
80 if (arg.equals("-help") || arg.equals("-h")) {
81 usage(0);
82 } else if (arg.equals(FORCE_SA_OPTION)) {
83 useSA = true;
84 } else {
85 if (option != null) {
86 usage(1); // option already specified
87 }
88 option = arg;
89 }
90 optionCount++;
91 }
92
93 // if no option provided then use default.
94 if (option == null) {
95 option = DEFAULT_OPTION;
96 }
97 if (option.matches(SA_TOOL_OPTIONS)) {
98 useSA = true;
99 }
100
101 // Next we check the parameter count. For the SA tools there are
102 // one or two parameters. For the built-in -dump option there is
103 // only one parameter (the process-id)
104 int paramCount = args.length - optionCount;
105 if (paramCount == 0 || paramCount > 2) {
106 usage(1);
107 }
108
109 if (optionCount == 0 || paramCount != 1) {
110 useSA = true;
111 } else {
112 // the parameter for the -dump option is a process-id.
113 // If it doesn't parse to a number then it must be SA
114 // debug server
115 if (!args[optionCount].matches("[0-9]+")) {
116 useSA = true;
117 }
118 }
119
120
121 // at this point we know if we are executing an SA tool or a built-in
122 // option.
123
124 if (useSA) {
125 // parameters (<pid> or <exe> <core>)
126 String params[] = new String[paramCount];
127 for (int i=optionCount; i<args.length; i++ ){
128 params[i-optionCount] = args[i];
129 }
130 runTool(option, params);
131
132 } else {
133 String pid = args[1];
134 // Here we handle the built-in options
135 // As more options are added we should create an abstract tool class and
136 // have a table to map the options
137 if (option.equals(HISTO_OPTION)) {
138 histo(pid, false);
139 } else if (option.equals(LIVE_HISTO_OPTION)) {
140 histo(pid, true);
141 } else if (option.startsWith(DUMP_OPTION_PREFIX)) {
142 dump(pid, option);
143 } else {
144 usage(1);
145 }
146 }
147 }
148
149 // Invoke SA tool with the given arguments
150 private static void runTool(String option, String args[]) throws Exception {
151 String[][] tools = {
152 { "-pmap", "sun.jvm.hotspot.tools.PMap" },
153 { "-heap", "sun.jvm.hotspot.tools.HeapSummary" },
154 { "-heap:format=b", "sun.jvm.hotspot.tools.HeapDumper" },
155 { "-histo", "sun.jvm.hotspot.tools.ObjectHistogram" },
156 { "-clstats", "sun.jvm.hotspot.tools.ClassLoaderStats" },
157 { "-finalizerinfo", "sun.jvm.hotspot.tools.FinalizerInfo" },
158 };
159
160 String tool = null;
161
162 // -dump option needs to be handled in a special way
163 if (option.startsWith(DUMP_OPTION_PREFIX)) {
164 // first check that the option can be parsed
165 String fn = parseDumpOptions(option);
166 if (fn == null) {
167 usage(1);
168 }
169
170 // tool for heap dumping
171 tool = "sun.jvm.hotspot.tools.HeapDumper";
172
173 // HeapDumper -f <file>
174 args = prepend(fn, args);
175 args = prepend("-f", args);
176 } else {
177 int i=0;
178 while (i < tools.length) {
179 if (option.equals(tools[i][0])) {
180 tool = tools[i][1];
181 break;
182 }
183 i++;
184 }
185 }
186 if (tool == null) {
187 usage(1); // no mapping to tool
188 }
189
190 // Tool not available on this platform.
191 Class<?> c = loadClass(tool);
192 if (c == null) {
193 usage(1);
194 }
195
196 // invoke the main method with the arguments
197 Class[] argTypes = { String[].class } ;
198 Method m = c.getDeclaredMethod("main", argTypes);
199
200 Object[] invokeArgs = { args };
201 m.invoke(null, invokeArgs);
202 }
203
204 // loads the given class using the system class loader
205 private static Class<?> loadClass(String name) {
206 //
207 // We specify the system clas loader so as to cater for development
208 // environments where this class is on the boot class path but sa-jdi.jar
209 // is on the system class path. Once the JDK is deployed then both
210 // tools.jar and sa-jdi.jar are on the system class path.
211 //
212 try {
213 return Class.forName(name, true,
214 ClassLoader.getSystemClassLoader());
215 } catch (Exception x) { }
216 return null;
217 }
218
219 private static final String LIVE_OBJECTS_OPTION = "-live";
220 private static final String ALL_OBJECTS_OPTION = "-all";
221 private static void histo(String pid, boolean live) throws IOException {
222 VirtualMachine vm = attach(pid);
223 InputStream in = ((HotSpotVirtualMachine)vm).
224 heapHisto(live ? LIVE_OBJECTS_OPTION : ALL_OBJECTS_OPTION);
225 drain(vm, in);
226 }
227
228 private static void dump(String pid, String options) throws IOException {
229 // parse the options to get the dump filename
230 String filename = parseDumpOptions(options);
231 if (filename == null) {
232 usage(1); // invalid options or no filename
233 }
234
235 // get the canonical path - important to avoid just passing
236 // a "heap.bin" and having the dump created in the target VM
237 // working directory rather than the directory where jmap
238 // is executed.
239 filename = new File(filename).getCanonicalPath();
240
241 // dump live objects only or not
242 boolean live = isDumpLiveObjects(options);
243
244 VirtualMachine vm = attach(pid);
245 System.out.println("Dumping heap to " + filename + " ...");
246 InputStream in = ((HotSpotVirtualMachine)vm).
247 dumpHeap((Object)filename,
248 (live ? LIVE_OBJECTS_OPTION : ALL_OBJECTS_OPTION));
249 drain(vm, in);
250 }
251
252 // Parse the options to the -dump option. Valid options are format=b and
328 } while (n > 0);
329 in.close();
330 vm.detach();
331 }
332
333 // return a new string array with arg as the first element
334 private static String[] prepend(String arg, String args[]) {
335 String[] newargs = new String[args.length+1];
336 newargs[0] = arg;
337 System.arraycopy(args, 0, newargs, 1, args.length);
338 return newargs;
339 }
340
341 // returns true if SA is available
342 private static boolean haveSA() {
343 Class<?> c = loadClass("sun.jvm.hotspot.tools.HeapSummary");
344 return (c != null);
345 }
346
347 // print usage message
348 private static void usage(int exit) {
349 System.err.println("Usage:");
350 if (haveSA()) {
351 System.err.println(" jmap [option] <pid>");
352 System.err.println(" (to connect to running process)");
353 System.err.println(" jmap [option] <executable <core>");
354 System.err.println(" (to connect to a core file)");
355 System.err.println(" jmap [option] [server_id@]<remote server IP or hostname>");
356 System.err.println(" (to connect to remote debug server)");
357 System.err.println("");
358 System.err.println("where <option> is one of:");
359 System.err.println(" <none> to print same info as Solaris pmap");
360 System.err.println(" -heap to print java heap summary");
361 System.err.println(" -histo[:live] to print histogram of java object heap; if the \"live\"");
362 System.err.println(" suboption is specified, only count live objects");
363 System.err.println(" -clstats to print class loader statistics");
364 System.err.println(" -finalizerinfo to print information on objects awaiting finalization");
365 System.err.println(" -dump:<dump-options> to dump java heap in hprof binary format");
366 System.err.println(" dump-options:");
367 System.err.println(" live dump only live objects; if not specified,");
368 System.err.println(" all objects in the heap are dumped.");
369 System.err.println(" format=b binary format");
370 System.err.println(" file=<file> dump heap to <file>");
371 System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
372 System.err.println(" -F force. Use with -dump:<dump-options> <pid> or -histo");
373 System.err.println(" to force a heap dump or histogram when <pid> does not");
374 System.err.println(" respond. The \"live\" suboption is not supported");
375 System.err.println(" in this mode.");
376 System.err.println(" -h | -help to print this help message");
377 System.err.println(" -J<flag> to pass <flag> directly to the runtime system");
378 } else {
379 System.err.println(" jmap -histo <pid>");
380 System.err.println(" (to connect to running process and print histogram of java object heap");
381 System.err.println(" jmap -dump:<dump-options> <pid>");
382 System.err.println(" (to connect to running process and dump java heap)");
383 System.err.println("");
384 System.err.println(" dump-options:");
385 System.err.println(" format=b binary default");
386 System.err.println(" file=<file> dump heap to <file>");
387 System.err.println("");
388 System.err.println(" Example: jmap -dump:format=b,file=heap.bin <pid>");
389 }
390
391 System.exit(exit);
392 }
393 }
|