225 } else { 226 bool live_objects_only = true; // default is true to retain the behavior before this change is made 227 const char* arg1 = op->arg(1); 228 if (arg1 != NULL && (strlen(arg1) > 0)) { 229 if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) { 230 out->print_cr("Invalid argument to dumpheap operation: %s", arg1); 231 return JNI_ERR; 232 } 233 live_objects_only = strcmp(arg1, "-live") == 0; 234 } 235 236 // Request a full GC before heap dump if live_objects_only = true 237 // This helps reduces the amount of unreachable objects in the dump 238 // and makes it easier to browse. 239 HeapDumper dumper(live_objects_only /* request GC */); 240 dumper.dump(op->arg(0), out); 241 } 242 return JNI_OK; 243 } 244 245 // Implementation of "inspectheap" command 246 // See also: ClassHistogramDCmd class 247 // 248 // Input arguments :- 249 // arg0: "-live" or "-all" 250 // arg1: Name of the dump file or NULL 251 static jint heap_inspection(AttachOperation* op, outputStream* out) { 252 bool live_objects_only = true; // default is true to retain the behavior before this change is made 253 outputStream* os = out; // if path not specified or path is NULL, use out 254 fileStream* fs = NULL; 255 const char* arg0 = op->arg(0); 256 if (arg0 != NULL && (strlen(arg0) > 0)) { 257 if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) { 258 out->print_cr("Invalid argument to inspectheap operation: %s", arg0); 259 return JNI_ERR; 260 } 261 live_objects_only = strcmp(arg0, "-live") == 0; 262 } 263 264 const char* path = op->arg(1); 265 if (path != NULL) { 266 if (path[0] == '\0') { 267 out->print_cr("No dump file specified"); 268 } else { 269 // create file 270 fs = new (ResourceObj::C_HEAP, mtInternal) fileStream(path); 271 if (fs == NULL) { 272 out->print_cr("Failed to allocate space for file: %s", path); 273 return JNI_ERR; 274 } 275 os = fs; 276 } 277 } 278 279 VM_GC_HeapInspection heapop(os, live_objects_only /* request full gc */); 280 VMThread::execute(&heapop); 281 if (os != NULL && os != out) { 282 out->print_cr("Heap inspection file created: %s", path); 283 delete fs; 284 } 285 return JNI_OK; 286 } 287 288 // Implementation of "setflag" command 289 static jint set_flag(AttachOperation* op, outputStream* out) { 290 291 const char* name = NULL; 292 if ((name = op->arg(0)) == NULL) { 293 out->print_cr("flag name is missing"); 294 return JNI_ERR; 295 } 296 297 FormatBuffer<80> err_msg("%s", ""); 298 299 int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); 300 if (ret != JVMFlag::SUCCESS) { 301 if (ret == JVMFlag::NON_WRITABLE) { 302 // if the flag is not manageable try to change it through 303 // the platform dependent implementation | 225 } else { 226 bool live_objects_only = true; // default is true to retain the behavior before this change is made 227 const char* arg1 = op->arg(1); 228 if (arg1 != NULL && (strlen(arg1) > 0)) { 229 if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) { 230 out->print_cr("Invalid argument to dumpheap operation: %s", arg1); 231 return JNI_ERR; 232 } 233 live_objects_only = strcmp(arg1, "-live") == 0; 234 } 235 236 // Request a full GC before heap dump if live_objects_only = true 237 // This helps reduces the amount of unreachable objects in the dump 238 // and makes it easier to browse. 239 HeapDumper dumper(live_objects_only /* request GC */); 240 dumper.dump(op->arg(0), out); 241 } 242 return JNI_OK; 243 } 244 245 // Valid Arguments: 246 // "-live" or "-all" 247 // "parallel=<N>" 248 // "<filepath>" 249 static jint process_heap_inspect_options(const char* argline, 250 outputStream* out, 251 HeapInspectArgs* args) { 252 char* save_ptr; 253 char* buf = NEW_C_HEAP_ARRAY(char, strlen(argline)+1, mtInternal); 254 snprintf(buf, strlen(argline)+1, "%s", argline); 255 if (buf == NULL) { 256 return JNI_ERR; 257 } 258 char* arg = strtok_r(buf, ",", &save_ptr); 259 while (arg != NULL) { 260 // "-live" or "-all" 261 if (strcmp(arg, "-live") == 0) { 262 args->_live_object_only = true; 263 } else if (strcmp(arg, "-all") == 0) { 264 args->_live_object_only = false; 265 } else if (strncmp(arg, "parallel=", 9) == 0) { 266 char* num_str = &arg[9]; 267 uintx num = 0; 268 if (!Arguments::parse_uintx(num_str, &num, 0)) { 269 out->print_cr("Invalid parallel thread number"); 270 return JNI_ERR; 271 } 272 args->_parallel_thread_num = num; 273 } else { 274 // must be file path 275 assert(args->_path == NULL, "Must be"); 276 char* path = args->_path = NEW_C_HEAP_ARRAY(char, strlen(arg)+1, mtInternal); 277 if (path == NULL) { 278 out->print_cr("Out of internal memory."); 279 return JNI_ERR; 280 } 281 snprintf(path, strlen(arg)+1, "%s", arg); 282 if (path[0] == '\0') { 283 out->print_cr("No dump file specified."); 284 } else { 285 fileStream* fs = new (ResourceObj::C_HEAP, mtInternal) fileStream(path); 286 if (fs == NULL) { 287 out->print_cr("Failed to allocate filestream for file: %s", path); 288 return JNI_ERR; 289 } 290 args->_fs = fs; 291 } 292 } 293 arg = strtok_r(NULL, ",", &save_ptr); 294 } 295 FREE_C_HEAP_ARRAY(char, buf); 296 return JNI_OK; 297 } 298 299 // Parse command options 300 static jint parse_cmd_options(const char* cmd, const char* argline, 301 outputStream* out, void* args) { 302 assert(argline != NULL, "Must be"); 303 if (strncmp(cmd, "heap_inspection", 11) == 0) { 304 HeapInspectArgs* insp_opts = (HeapInspectArgs*)args; 305 return process_heap_inspect_options(argline, out, insp_opts); 306 } 307 // Command not match 308 return JNI_ERR; 309 } 310 311 // Implementation of "inspectheap" command 312 // See also: ClassHistogramDCmd class 313 // 314 // Input arguments :- 315 // all arguments in op->arg(0); 316 static jint heap_inspection(AttachOperation* op, outputStream* out) { 317 bool live_objects_only = true; // default is true to retain the behavior before this change is made 318 outputStream* os = out; // if path not specified or path is NULL, use out 319 const char* arg0 = op->arg(0); 320 size_t parallel_thread_num = os::processor_count() * 3 / 8; // default is less than half of processors. 321 HeapInspectArgs args; 322 // Parse arguments 323 if (arg0 != NULL) { 324 if (JNI_ERR == parse_cmd_options("heap_inspection", arg0, out, (void*)(&args))) { 325 return JNI_ERR; 326 } 327 live_objects_only = args._live_object_only; 328 os = args._fs == NULL ? out : args._fs; 329 parallel_thread_num = args._parallel_thread_num == 0 ? parallel_thread_num : args._parallel_thread_num; 330 if (parallel_thread_num == 0) { 331 parallel_thread_num = 1; 332 } 333 } 334 335 VM_GC_HeapInspection heapop(os, live_objects_only /* request full gc */, parallel_thread_num); 336 VMThread::execute(&heapop); 337 if (args._path != NULL) { 338 out->print_cr("Heap inspection file created: %s", args._path); 339 } 340 return JNI_OK; 341 } 342 343 // Implementation of "setflag" command 344 static jint set_flag(AttachOperation* op, outputStream* out) { 345 346 const char* name = NULL; 347 if ((name = op->arg(0)) == NULL) { 348 out->print_cr("flag name is missing"); 349 return JNI_ERR; 350 } 351 352 FormatBuffer<80> err_msg("%s", ""); 353 354 int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); 355 if (ret != JVMFlag::SUCCESS) { 356 if (ret == JVMFlag::NON_WRITABLE) { 357 // if the flag is not manageable try to change it through 358 // the platform dependent implementation |