8256450: Add gz option to jmap to write a gzipped heap dump
Reviewed-by: cjplummer, sspitsyn, phh
This commit is contained in:
parent
dee79d6053
commit
461c5fc637
@ -218,6 +218,7 @@ static jint jcmd(AttachOperation* op, outputStream* out) {
|
|||||||
// Input arguments :-
|
// Input arguments :-
|
||||||
// arg0: Name of the dump file
|
// arg0: Name of the dump file
|
||||||
// arg1: "-live" or "-all"
|
// arg1: "-live" or "-all"
|
||||||
|
// arg2: Compress level
|
||||||
jint dump_heap(AttachOperation* op, outputStream* out) {
|
jint dump_heap(AttachOperation* op, outputStream* out) {
|
||||||
const char* path = op->arg(0);
|
const char* path = op->arg(0);
|
||||||
if (path == NULL || path[0] == '\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;
|
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
|
// Request a full GC before heap dump if live_objects_only = true
|
||||||
// This helps reduces the amount of unreachable objects in the dump
|
// This helps reduces the amount of unreachable objects in the dump
|
||||||
// and makes it easier to browse.
|
// and makes it easier to browse.
|
||||||
HeapDumper dumper(live_objects_only /* request GC */);
|
HeapDumper dumper(live_objects_only /* request GC */);
|
||||||
dumper.dump(op->arg(0), out);
|
dumper.dump(op->arg(0), out, (int)level);
|
||||||
}
|
}
|
||||||
return JNI_OK;
|
return JNI_OK;
|
||||||
}
|
}
|
||||||
|
@ -209,6 +209,7 @@ public class JMap {
|
|||||||
String subopts[] = options.split(",");
|
String subopts[] = options.split(",");
|
||||||
String filename = null;
|
String filename = null;
|
||||||
String liveopt = "-all";
|
String liveopt = "-all";
|
||||||
|
String compress_level = null;
|
||||||
|
|
||||||
for (int i = 0; i < subopts.length; i++) {
|
for (int i = 0; i < subopts.length; i++) {
|
||||||
String subopt = subopts[i];
|
String subopt = subopts[i];
|
||||||
@ -224,6 +225,12 @@ public class JMap {
|
|||||||
}
|
}
|
||||||
} else if (subopt.equals("format=b")) {
|
} else if (subopt.equals("format=b")) {
|
||||||
// ignore format (not needed at this time)
|
// 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 {
|
} else {
|
||||||
System.err.println("Fail: invalid option: '" + subopt + "'");
|
System.err.println("Fail: invalid option: '" + subopt + "'");
|
||||||
usage(1);
|
usage(1);
|
||||||
@ -238,7 +245,7 @@ public class JMap {
|
|||||||
System.out.flush();
|
System.out.flush();
|
||||||
|
|
||||||
// dumpHeap is not the same as jcmd GC.heap_dump
|
// 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) {
|
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(" 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(" format=b binary format");
|
||||||
System.err.println(" file=<file> dump heap to <file>");
|
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("");
|
||||||
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
|
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
|
||||||
System.err.println("");
|
System.err.println("");
|
||||||
|
@ -22,10 +22,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import static jdk.test.lib.Asserts.assertTrue;
|
import static jdk.test.lib.Asserts.assertTrue;
|
||||||
|
import static jdk.test.lib.Asserts.assertFalse;
|
||||||
import static jdk.test.lib.Asserts.fail;
|
import static jdk.test.lib.Asserts.fail;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import jdk.test.lib.JDKToolLauncher;
|
import jdk.test.lib.JDKToolLauncher;
|
||||||
import jdk.test.lib.Utils;
|
import jdk.test.lib.Utils;
|
||||||
@ -114,6 +117,7 @@ public class BasicJMapTest {
|
|||||||
testDump();
|
testDump();
|
||||||
testDumpLive();
|
testDumpLive();
|
||||||
testDumpAll();
|
testDumpAll();
|
||||||
|
testDumpCompressed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testHisto() throws Exception {
|
private static void testHisto() throws Exception {
|
||||||
@ -211,20 +215,25 @@ public class BasicJMapTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void testDump() throws Exception {
|
private static void testDump() throws Exception {
|
||||||
dump(false, false);
|
dump(false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testDumpLive() throws Exception {
|
private static void testDumpLive() throws Exception {
|
||||||
dump(true, false);
|
dump(true, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void testDumpAll() throws Exception {
|
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 liveArg = "";
|
||||||
String fileArg = "";
|
String fileArg = "";
|
||||||
|
String compressArg = "";
|
||||||
String allArgs = "-dump:";
|
String allArgs = "-dump:";
|
||||||
|
|
||||||
if (live && explicitAll) {
|
if (live && explicitAll) {
|
||||||
@ -237,14 +246,20 @@ public class BasicJMapTest {
|
|||||||
liveArg = "all,";
|
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()) {
|
if (file.exists()) {
|
||||||
file.delete();
|
file.delete();
|
||||||
}
|
}
|
||||||
fileArg = "file=" + file.getName();
|
fileArg = "file=" + file.getName();
|
||||||
|
|
||||||
OutputAnalyzer output;
|
OutputAnalyzer output;
|
||||||
allArgs = allArgs + liveArg + "format=b," + fileArg;
|
allArgs = allArgs + liveArg + compressArg + "format=b," + fileArg;
|
||||||
output = jmap(allArgs);
|
output = jmap(allArgs);
|
||||||
output.shouldHaveExitValue(0);
|
output.shouldHaveExitValue(0);
|
||||||
output.shouldContain("Heap dump file created");
|
output.shouldContain("Heap dump file created");
|
||||||
@ -255,7 +270,18 @@ public class BasicJMapTest {
|
|||||||
private static void verifyDumpFile(File dump) {
|
private static void verifyDumpFile(File dump) {
|
||||||
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
|
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
|
||||||
try {
|
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) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
fail("Could not parse dump file " + dump.getAbsolutePath());
|
fail("Could not parse dump file " + dump.getAbsolutePath());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user