< prev index next > src/java.base/share/classes/jdk/internal/vm/ThreadDumper.java
Print this page
* Generate a thread dump in plain text format to a file or byte array, UTF-8 encoded.
* This method is invoked by the VM for the Thread.dump_to_file diagnostic command.
*
* @param file the file path to the file, null or "-" to return a byte array
* @param okayToOverwrite true to overwrite an existing file
* @return the UTF-8 encoded thread dump or message to return to the tool user
*/
! public static byte[] dumpThreads(String file, boolean okayToOverwrite) {
if (file == null || file.equals("-")) {
! return dumpThreadsToByteArray(false, MAX_BYTE_ARRAY_SIZE);
} else {
! return dumpThreadsToFile(file, okayToOverwrite, false);
}
}
/**
* Generate a thread dump in JSON format to a file or byte array, UTF-8 encoded.
* Generate a thread dump in plain text format to a file or byte array, UTF-8 encoded.
* This method is invoked by the VM for the Thread.dump_to_file diagnostic command.
*
* @param file the file path to the file, null or "-" to return a byte array
* @param okayToOverwrite true to overwrite an existing file
+ * @param ignore not used
* @return the UTF-8 encoded thread dump or message to return to the tool user
*/
! public static byte[] dumpThreads(String file, boolean okayToOverwrite, boolean ignore) {
if (file == null || file.equals("-")) {
! return dumpThreadsToByteArray(false, false, MAX_BYTE_ARRAY_SIZE);
} else {
! return dumpThreadsToFile(file, okayToOverwrite, false, false);
}
}
/**
* Generate a thread dump in JSON format to a file or byte array, UTF-8 encoded.
*
* @param file the file path to the file, null or "-" to return a byte array
* @param okayToOverwrite true to overwrite an existing file
* @return the UTF-8 encoded thread dump or message to return to the tool user
*/
! public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite) {
if (file == null || file.equals("-")) {
! return dumpThreadsToByteArray(true, MAX_BYTE_ARRAY_SIZE);
} else {
! return dumpThreadsToFile(file, okayToOverwrite, true);
}
}
/**
* Generate a thread dump in plain text or JSON format to a byte array, UTF-8 encoded.
* This method is the implementation of the Thread.dump_to_file diagnostic command
* when a file path is not specified. It returns the thread dump and/or message to
* send to the tool user.
*/
! private static byte[] dumpThreadsToByteArray(boolean json, int maxSize) {
var out = new BoundedByteArrayOutputStream(maxSize);
try (out; var writer = new TextWriter(out)) {
if (json) {
! dumpThreadsToJson(writer);
} else {
dumpThreads(writer);
}
} catch (Exception ex) {
if (ex instanceof UncheckedIOException ioe) {
*
* @param file the file path to the file, null or "-" to return a byte array
* @param okayToOverwrite true to overwrite an existing file
* @return the UTF-8 encoded thread dump or message to return to the tool user
*/
! public static byte[] dumpThreadsToJson(String file, boolean okayToOverwrite, boolean minify) {
if (file == null || file.equals("-")) {
! return dumpThreadsToByteArray(true, !minify, MAX_BYTE_ARRAY_SIZE);
} else {
! return dumpThreadsToFile(file, okayToOverwrite, true, minify);
}
}
/**
* Generate a thread dump in plain text or JSON format to a byte array, UTF-8 encoded.
* This method is the implementation of the Thread.dump_to_file diagnostic command
* when a file path is not specified. It returns the thread dump and/or message to
* send to the tool user.
*/
! private static byte[] dumpThreadsToByteArray(boolean json, boolean minify, int maxSize) {
var out = new BoundedByteArrayOutputStream(maxSize);
try (out; var writer = new TextWriter(out)) {
if (json) {
! dumpThreadsToJson(writer, minify);
} else {
dumpThreads(writer);
}
} catch (Exception ex) {
if (ex instanceof UncheckedIOException ioe) {
/**
* Generate a thread dump in plain text or JSON format to the given file, UTF-8 encoded.
* This method is the implementation of the Thread.dump_to_file diagnostic command.
* It returns the thread dump and/or message to send to the tool user.
*/
! private static byte[] dumpThreadsToFile(String file, boolean okayToOverwrite, boolean json) {
Path path = Path.of(file).toAbsolutePath();
OpenOption[] options = (okayToOverwrite)
? new OpenOption[0]
: new OpenOption[] { StandardOpenOption.CREATE_NEW };
String reply;
try (OutputStream out = Files.newOutputStream(path, options)) {
try (var writer = new TextWriter(out)) {
if (json) {
! dumpThreadsToJson(writer);
} else {
dumpThreads(writer);
}
reply = String.format("Created %s%n", path);
} catch (UncheckedIOException e) {
/**
* Generate a thread dump in plain text or JSON format to the given file, UTF-8 encoded.
* This method is the implementation of the Thread.dump_to_file diagnostic command.
* It returns the thread dump and/or message to send to the tool user.
*/
! private static byte[] dumpThreadsToFile(String file,
+ boolean okayToOverwrite,
+ boolean json,
+ boolean minify) {
Path path = Path.of(file).toAbsolutePath();
OpenOption[] options = (okayToOverwrite)
? new OpenOption[0]
: new OpenOption[] { StandardOpenOption.CREATE_NEW };
String reply;
try (OutputStream out = Files.newOutputStream(path, options)) {
try (var writer = new TextWriter(out)) {
if (json) {
! dumpThreadsToJson(writer, minify);
} else {
dumpThreads(writer);
}
reply = String.format("Created %s%n", path);
} catch (UncheckedIOException e) {
}
private static boolean dumpThread(Thread thread, TextWriter writer) {
ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
if (snapshot == null) {
! return false; // thread terminated
}
Instant now = Instant.now();
Thread.State state = snapshot.threadState();
writer.println("#" + thread.threadId() + " \"" + snapshot.threadName()
+ "\" " + (thread.isVirtual() ? "virtual " : "") + state + " " + now);
}
private static boolean dumpThread(Thread thread, TextWriter writer) {
ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
if (snapshot == null) {
! return false; // thread not alive
}
Instant now = Instant.now();
Thread.State state = snapshot.threadState();
writer.println("#" + thread.threadId() + " \"" + snapshot.threadName()
+ "\" " + (thread.isVirtual() ? "virtual " : "") + state + " " + now);
* @throws IOException if an I/O error occurs
*/
public static void dumpThreadsToJson(OutputStream out) throws IOException {
var writer = new TextWriter(out);
try {
! dumpThreadsToJson(writer);
writer.flush();
} catch (UncheckedIOException e) {
IOException ioe = e.getCause();
throw ioe;
}
* @throws IOException if an I/O error occurs
*/
public static void dumpThreadsToJson(OutputStream out) throws IOException {
var writer = new TextWriter(out);
try {
! dumpThreadsToJson(writer, /*prettyPrint*/ true);
writer.flush();
} catch (UncheckedIOException e) {
IOException ioe = e.getCause();
throw ioe;
}
/**
* Generate a thread dump to the given text stream in JSON format.
* @throws UncheckedIOException if an I/O error occurs
*/
! private static void dumpThreadsToJson(TextWriter textWriter) {
! var jsonWriter = new JsonWriter(textWriter);
jsonWriter.startObject(); // top-level object
jsonWriter.startObject("threadDump");
/**
* Generate a thread dump to the given text stream in JSON format.
* @throws UncheckedIOException if an I/O error occurs
*/
! private static void dumpThreadsToJson(TextWriter textWriter, boolean minify) {
! var jsonWriter = new JsonWriter(textWriter, minify);
jsonWriter.startObject(); // top-level object
jsonWriter.startObject("threadDump");
*/
private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) {
Instant now = Instant.now();
ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
if (snapshot == null) {
! return false; // thread terminated
}
Thread.State state = snapshot.threadState();
StackTraceElement[] stackTrace = snapshot.stackTrace();
jsonWriter.startObject();
*/
private static boolean dumpThread(Thread thread, JsonWriter jsonWriter) {
Instant now = Instant.now();
ThreadSnapshot snapshot = ThreadSnapshot.of(thread);
if (snapshot == null) {
! return false; // thread not alive
}
Thread.State state = snapshot.threadState();
StackTraceElement[] stackTrace = snapshot.stackTrace();
jsonWriter.startObject();
return old;
}
}
private final Deque<Node> stack = new ArrayDeque<>();
private final TextWriter writer;
! JsonWriter(TextWriter writer) {
this.writer = writer;
}
private void indent() {
! int indent = stack.size() * 2;
! writer.print(" ".repeat(indent));
}
/**
* Start of object or array.
*/
private void startObject(String name, boolean isArray) {
if (!stack.isEmpty()) {
Node node = stack.peek();
if (node.getAndIncrementPropertyCount() > 0) {
! writer.println(",");
}
}
indent();
if (name != null) {
! writer.print("\"" + name + "\": ");
}
! writer.println(isArray ? "[" : "{");
stack.push(new Node(isArray));
}
/**
* End of object or array.
return old;
}
}
private final Deque<Node> stack = new ArrayDeque<>();
private final TextWriter writer;
+ private final boolean prettyPrint; // pretty print or minify
! JsonWriter(TextWriter writer, boolean minify) {
this.writer = writer;
+ this.prettyPrint = !minify;
+ }
+
+ private void print(Object obj) {
+ writer.print(obj);
+ }
+
+ private void println(Object obj) {
+ if (prettyPrint) {
+ writer.println(obj);
+ } else {
+ writer.print(obj);
+ }
+ }
+
+ private void println() {
+ if (prettyPrint) {
+ writer.println();
+ }
}
private void indent() {
! if (prettyPrint) {
! int indent = stack.size() * 2;
+ writer.print(" ".repeat(indent));
+ }
}
/**
* Start of object or array.
*/
private void startObject(String name, boolean isArray) {
if (!stack.isEmpty()) {
Node node = stack.peek();
if (node.getAndIncrementPropertyCount() > 0) {
! println(",");
}
}
indent();
if (name != null) {
! String gap = prettyPrint ? " " : "";
+ print("\"" + name + "\":" + gap);
}
! println(isArray ? "[" : "{");
stack.push(new Node(isArray));
}
/**
* End of object or array.
private void endObject(boolean isArray) {
Node node = stack.pop();
if (node.isArray() != isArray)
throw new IllegalStateException();
if (node.propertyCount() > 0) {
! writer.println();
}
indent();
! writer.print(isArray ? "]" : "}");
}
/**
* Write a property.
* @param name the property name, null for an unnamed property
* @param obj the value or null
*/
void writeProperty(String name, Object obj) {
Node node = stack.peek();
if (node.getAndIncrementPropertyCount() > 0) {
! writer.println(",");
}
indent();
if (name != null) {
! writer.print("\"" + name + "\": ");
}
switch (obj) {
// Long may be larger than safe range of JSON integer value
! case Long _ -> writer.print("\"" + obj + "\"");
! case Number _ -> writer.print(obj);
! case Boolean _ -> writer.print(obj);
! case null -> writer.print("null");
! default -> writer.print("\"" + escape(obj.toString()) + "\"");
}
}
/**
* Write an unnamed property.
private void endObject(boolean isArray) {
Node node = stack.pop();
if (node.isArray() != isArray)
throw new IllegalStateException();
if (node.propertyCount() > 0) {
! println();
}
indent();
! print(isArray ? "]" : "}");
}
/**
* Write a property.
* @param name the property name, null for an unnamed property
* @param obj the value or null
*/
void writeProperty(String name, Object obj) {
Node node = stack.peek();
+ assert node != null;
if (node.getAndIncrementPropertyCount() > 0) {
! println(",");
}
indent();
if (name != null) {
! print("\"" + name + "\": ");
}
switch (obj) {
// Long may be larger than safe range of JSON integer value
! case Long _ -> print("\"" + obj + "\"");
! case Number _ -> print(obj);
! case Boolean _ -> print(obj);
! case null -> print("null");
! default -> print("\"" + escape(obj.toString()) + "\"");
}
}
/**
* Write an unnamed property.
< prev index next >