8256450: Add gz option to jmap to write a gzipped heap dump

Reviewed-by: cjplummer, sspitsyn, phh
This commit is contained in:
Lin Zang 2020-11-25 16:51:42 +00:00 committed by Paul Hohensee
parent dee79d6053
commit 461c5fc637
3 changed files with 56 additions and 9 deletions

View File

@ -218,6 +218,7 @@ static jint jcmd(AttachOperation* op, outputStream* out) {
// Input arguments :-
// arg0: Name of the dump file
// arg1: "-live" or "-all"
// arg2: Compress level
jint dump_heap(AttachOperation* op, outputStream* out) {
const char* path = op->arg(0);
if (path == NULL || path[0] == '\0') {
@ -233,11 +234,22 @@ jint dump_heap(AttachOperation* op, outputStream* out) {
live_objects_only = strcmp(arg1, "-live") == 0;
}
const char* num_str = op->arg(2);
uintx level = 0;
if (num_str != NULL && num_str[0] != '\0') {
if (!Arguments::parse_uintx(num_str, &level, 0)) {
out->print_cr("Invalid compress level: [%s]", num_str);
return JNI_ERR;
} else if (level < 1 || level > 9) {
out->print_cr("Compression level out of range (1-9): " UINTX_FORMAT, level);
return JNI_ERR;
}
}
// Request a full GC before heap dump if live_objects_only = true
// This helps reduces the amount of unreachable objects in the dump
// and makes it easier to browse.
HeapDumper dumper(live_objects_only /* request GC */);
dumper.dump(op->arg(0), out);
dumper.dump(op->arg(0), out, (int)level);
}
return JNI_OK;
}

View File

@ -209,6 +209,7 @@ public class JMap {
String subopts[] = options.split(",");
String filename = null;
String liveopt = "-all";
String compress_level = null;
for (int i = 0; i < subopts.length; i++) {
String subopt = subopts[i];
@ -224,6 +225,12 @@ public class JMap {
}
} else if (subopt.equals("format=b")) {
// ignore format (not needed at this time)
} else if (subopt.startsWith("gz=")) {
compress_level = subopt.substring("gz=".length());
if (compress_level == null) {
System.err.println("Fail: no number provided in option: '" + subopt + "'");
usage(1);
}
} else {
System.err.println("Fail: invalid option: '" + subopt + "'");
usage(1);
@ -238,7 +245,7 @@ public class JMap {
System.out.flush();
// dumpHeap is not the same as jcmd GC.heap_dump
executeCommandForPid(pid, "dumpheap", filename, liveopt);
executeCommandForPid(pid, "dumpheap", filename, liveopt, compress_level);
}
private static void checkForUnsupportedOptions(String[] args) {
@ -303,6 +310,8 @@ public class JMap {
System.err.println(" all dump all objects in the heap (default if one of \"live\" or \"all\" is not specified)");
System.err.println(" format=b binary format");
System.err.println(" file=<file> dump heap to <file>");
System.err.println(" gz=<number> If specified, the heap dump is written in gzipped format using the given compression level.");
System.err.println(" 1 (recommended) is the fastest, 9 the strongest compression.");
System.err.println("");
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
System.err.println("");

View File

@ -22,10 +22,13 @@
*/
import static jdk.test.lib.Asserts.assertTrue;
import static jdk.test.lib.Asserts.assertFalse;
import static jdk.test.lib.Asserts.fail;
import java.io.File;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.Utils;
@ -114,6 +117,7 @@ public class BasicJMapTest {
testDump();
testDumpLive();
testDumpAll();
testDumpCompressed();
}
private static void testHisto() throws Exception {
@ -211,20 +215,25 @@ public class BasicJMapTest {
}
private static void testDump() throws Exception {
dump(false, false);
dump(false, false, false);
}
private static void testDumpLive() throws Exception {
dump(true, false);
dump(true, false, false);
}
private static void testDumpAll() throws Exception {
dump(false, true);
dump(false, true, false);
}
private static void dump(boolean live, boolean explicitAll) throws Exception {
private static void testDumpCompressed() throws Exception {
dump(true, false, true);
}
private static void dump(boolean live, boolean explicitAll, boolean compressed) throws Exception {
String liveArg = "";
String fileArg = "";
String compressArg = "";
String allArgs = "-dump:";
if (live && explicitAll) {
@ -237,14 +246,20 @@ public class BasicJMapTest {
liveArg = "all,";
}
File file = new File("jmap.dump" + System.currentTimeMillis() + ".hprof");
String filePath = "jmap.dump" + System.currentTimeMillis() + ".hprof";
if (compressed) {
compressArg = "gz=1,";
filePath = filePath + ".gz";
}
File file = new File(filePath);
if (file.exists()) {
file.delete();
}
fileArg = "file=" + file.getName();
OutputAnalyzer output;
allArgs = allArgs + liveArg + "format=b," + fileArg;
allArgs = allArgs + liveArg + compressArg + "format=b," + fileArg;
output = jmap(allArgs);
output.shouldHaveExitValue(0);
output.shouldContain("Heap dump file created");
@ -255,7 +270,18 @@ public class BasicJMapTest {
private static void verifyDumpFile(File dump) {
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
try {
HprofParser.parse(dump);
File out = HprofParser.parse(dump);
assertTrue(out != null && out.exists() && out.isFile(),
"Could not find hprof parser output file");
List<String> lines = Files.readAllLines(out.toPath());
assertTrue(lines.size() > 0, "hprof parser output file is empty");
for (String line : lines) {
assertFalse(line.matches(".*WARNING(?!.*Failed to resolve " +
"object.*constantPoolOop.*).*"));
}
out.delete();
} catch (Exception e) {
e.printStackTrace();
fail("Could not parse dump file " + dump.getAbsolutePath());