History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/tools/jmap/JMap.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/tools/jmap/JMap.java+389−0
@@ -0,0 +1,389 @@
1+/*
2+ * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package sun.tools.jmap;
27+
28+import java.lang.reflect.Method;
29+import java.io.File;
30+import java.io.IOException;
31+import java.io.InputStream;
32+
33+import com.sun.tools.attach.VirtualMachine;
34+import com.sun.tools.attach.AttachNotSupportedException;
35+import sun.tools.attach.HotSpotVirtualMachine;
36+
37+/*
38+ * This class is the main class for the JMap utility. It parses its arguments
39+ * and decides if the command should be satisifed using the VM attach mechanism
40+ * or an SA tool. At this time the only option that uses the VM attach mechanism
41+ * is the -dump option to get a heap dump of a running application. All other
42+ * options are mapped to SA tools.
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|-permstat|-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+ { "-permstat", "sun.jvm.hotspot.tools.PermStat" },
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
249+ // file=<file>. Returns <file> if provided. Returns null if <file> not
250+ // provided, or invalid option.
251+ private static String parseDumpOptions(String arg) {
252+ assert arg.startsWith(DUMP_OPTION_PREFIX);
253+
254+ String filename = null;
255+
256+ // options are separated by comma (,)
257+ String options[] = arg.substring(DUMP_OPTION_PREFIX.length()).split(",");
258+
259+ for (int i=0; i<options.length; i++) {
260+ String option = options[i];
261+
262+ if (option.equals("format=b")) {
263+ // ignore format (not needed at this time)
264+ } else if (option.equals("live")) {
265+ // a valid suboption
266+ } else {
267+
268+ // file=<file> - check that <file> is specified
269+ if (option.startsWith("file=")) {
270+ filename = option.substring(5);
271+ if (filename.length() == 0) {
272+ return null;
273+ }
274+ } else {
275+ return null; // option not recognized
276+ }
277+ }
278+ }
279+ return filename;
280+ }
281+
282+ private static boolean isDumpLiveObjects(String arg) {
283+ // options are separated by comma (,)
284+ String options[] = arg.substring(DUMP_OPTION_PREFIX.length()).split(",");
285+ for (String suboption : options) {
286+ if (suboption.equals("live")) {
287+ return true;
288+ }
289+ }
290+ return false;
291+ }
292+
293+ // Attach to <pid>, existing if we fail to attach
294+ private static VirtualMachine attach(String pid) {
295+ try {
296+ return VirtualMachine.attach(pid);
297+ } catch (Exception x) {
298+ String msg = x.getMessage();
299+ if (msg != null) {
300+ System.err.println(pid + ": " + msg);
301+ } else {
302+ x.printStackTrace();
303+ }
304+ if ((x instanceof AttachNotSupportedException) && haveSA()) {
305+ System.err.println("The -F option can be used when the " +
306+ "target process is not responding");
307+ }
308+ System.exit(1);
309+ return null; // keep compiler happy
310+ }
311+ }
312+
313+ // Read the stream from the target VM until EOF, then detach
314+ private static void drain(VirtualMachine vm, InputStream in) throws IOException {
315+ // read to EOF and just print output
316+ byte b[] = new byte[256];
317+ int n;
318+ do {
319+ n = in.read(b);
320+ if (n > 0) {
321+ String s = new String(b, 0, n, "UTF-8");
322+ System.out.print(s);
323+ }
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(" -permstat to print permanent generation 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+}