src/share/classes/sun/tools/jmap/JMap.java

Print this page
rev 8717 : 8027765: Make exit codes and stdout/stderr printing from jmap/jinfo/jstack/jps consistent
Reviewed-by:


  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 }