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 | 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 // arg2: parallel thread number 252 static jint heap_inspection(AttachOperation* op, outputStream* out) { 253 bool live_objects_only = true; // default is true to retain the behavior before this change is made 254 outputStream* os = out; // if path not specified or path is NULL, use out 255 fileStream* fs = NULL; 256 const char* arg0 = op->arg(0); 257 uint parallel_thread_num = MAX2<uint>(1, (uint)os::initial_active_processor_count() * 3 / 8); 258 if (arg0 != NULL && (strlen(arg0) > 0)) { 259 if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) { 260 out->print_cr("Invalid argument to inspectheap operation: %s", arg0); 261 return JNI_ERR; 262 } 263 live_objects_only = strcmp(arg0, "-live") == 0; 264 } 265 266 const char* path = op->arg(1); 267 if (path != NULL && path[0] != '\0') { 268 // create file 269 fs = new (ResourceObj::C_HEAP, mtInternal) fileStream(path); 270 if (fs == NULL) { 271 out->print_cr("Failed to allocate space for file: %s", path); 272 } 273 os = fs; 274 } 275 276 const char* num_str = op->arg(2); 277 if (num_str != NULL && num_str[0] != '\0') { 278 uintx num; 279 if (!Arguments::parse_uintx(num_str, &num, 0)) { 280 out->print_cr("Invalid parallel thread number: [%s]", num_str); 281 return JNI_ERR; 282 } 283 parallel_thread_num = num == 0 ? parallel_thread_num : (uint)num; 284 } 285 286 VM_GC_HeapInspection heapop(os, live_objects_only /* request full gc */, parallel_thread_num); 287 VMThread::execute(&heapop); 288 if (os != NULL && os != out) { 289 out->print_cr("Heap inspection file created: %s", path); 290 delete fs; 291 } 292 return JNI_OK; 293 } 294 295 // Implementation of "setflag" command 296 static jint set_flag(AttachOperation* op, outputStream* out) { 297 298 const char* name = NULL; 299 if ((name = op->arg(0)) == NULL) { 300 out->print_cr("flag name is missing"); 301 return JNI_ERR; 302 } 303 304 FormatBuffer<80> err_msg("%s", ""); 305 306 int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); 307 if (ret != JVMFlag::SUCCESS) { 308 if (ret == JVMFlag::NON_WRITABLE) { 309 // if the flag is not manageable try to change it through 310 // the platform dependent implementation |