Skip to content
Permalink
Browse files
8257234: Add gz option to SA jmap to write a gzipped heap dump
Reviewed-by: cjplummer, ysuenaga, sspitsyn
  • Loading branch information
Lin Zang authored and DamonFool committed Feb 25, 2021
1 parent aa35b42 commit c54724da143bb96da9c3534539bc789847858464
Show file tree
Hide file tree
Showing 7 changed files with 634 additions and 105 deletions.
@@ -163,7 +163,6 @@ void add(String s, ArrayList<String> t) {

Tokens(String cmd) {
input = cmd;

// check for quoting
int quote = cmd.indexOf('"');
ArrayList<String> t = new ArrayList<>();
@@ -1787,25 +1786,60 @@ public void doit(Tokens t) {
sysProps.run();
}
},
new Command("dumpheap", "dumpheap [filename]", false) {
new Command("dumpheap", "dumpheap [gz=<1-9>] [filename]", false) {
public void doit(Tokens t) {
if (t.countTokens() > 1) {
int cntTokens = t.countTokens();
if (cntTokens > 2) {
err.println("More than 2 options specified: " + cntTokens);
usage();
} else {
JMap jmap = new JMap();
String filename;
if (t.countTokens() == 1) {
filename = t.nextToken();
return;
}
JMap jmap = new JMap();
String filename = "heap.bin";
int gzlevel = 0;
/*
* Possible command:
* dumpheap gz=1 file;
* dumpheap gz=1;
* dumpheap file;
* dumpheap
*
* Use default filename if cntTokens == 0.
* Handle cases with cntTokens == 1 or 2.
*/
if (cntTokens == 1) { // first argument could be filename or "gz="
String option = t.nextToken();
if (!option.startsWith("gz=")) {
filename = option;
} else {
filename = "heap.bin";;
}
try {
jmap.writeHeapHprofBin(filename);
} catch (Exception e) {
err.println("Error: " + e);
if (verboseExceptions) {
e.printStackTrace(err);
gzlevel = parseHeapDumpCompressionLevel(option);
if (gzlevel == 0) {
usage();
return;
}
filename = "heap.bin.gz";
}
}
if (cntTokens == 2) { // first argument is "gz=" followed by filename
String option = t.nextToken();
gzlevel = parseHeapDumpCompressionLevel(option);
if (gzlevel == 0) {
usage();
return;
}
filename = t.nextToken();
if (filename.startsWith("gz=")) {
err.println("Filename should not start with \"gz=\": " + filename);
usage();
return;
}
}
try {
jmap.writeHeapHprofBin(filename, gzlevel);
} catch (Exception e) {
err.println("Error: " + e);
if (verboseExceptions) {
e.printStackTrace(err);
}
}
}
@@ -2080,4 +2114,34 @@ void executeCommand(Tokens args) {
}
}
}

/* Parse compression level
* @return 1-9 compression level
* 0 compression level is illegal
*/
private int parseHeapDumpCompressionLevel(String option) {

String[] keyValue = option.split("=");
if (!keyValue[0].equals("gz")) {
err.println("Expected option is \"gz=\"");
return 0;
}
if (keyValue.length != 2) {
err.println("Exactly one argument is expected for option \"gz\"");
return 0;
}
int gzl = 0;
String level = keyValue[1];
try {
gzl = Integer.parseInt(level);
} catch (NumberFormatException e) {
err.println("gz option value not an integer ("+level+")");
return 0;
}
if (gzl < 1 || gzl > 9) {
err.println("Compression level out of range (1-9): " + level);
return 0;
}
return gzl;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -126,7 +126,8 @@ private static boolean jmapHelp() {
System.out.println(" <no option> To print same info as Solaris pmap.");
System.out.println(" --heap To print java heap summary.");
System.out.println(" --binaryheap To dump java heap in hprof binary format.");
System.out.println(" --dumpfile <name> The name of the dump file.");
System.out.println(" --dumpfile <name> The name of the dump file. Only valid with --binaryheap.");
System.out.println(" --gz <1-9> The compression level for gzipped dump file. Only valid with --binaryheap.");
System.out.println(" --histo To print histogram of java object heap.");
System.out.println(" --clstats To print class loader statistics.");
System.out.println(" --finalizerinfo To print information on objects awaiting finalization.");
@@ -301,33 +302,40 @@ private static void runJSTACK(String[] oldArgs) {
}

private static void runJMAP(String[] oldArgs) {
Map<String, String> longOptsMap = Map.of("exe=", "exe",
"core=", "core",
"pid=", "pid",
"connect=", "connect",
"heap", "-heap",
"binaryheap", "binaryheap",
"dumpfile=", "dumpfile",
"histo", "-histo",
"clstats", "-clstats",
"finalizerinfo", "-finalizerinfo");
Map<String, String> longOptsMap = Map.ofEntries(
Map.entry("exe=", "exe"),
Map.entry("core=", "core"),
Map.entry("pid=", "pid"),
Map.entry("connect=", "connect"),
Map.entry("heap", "-heap"),
Map.entry("binaryheap", "binaryheap"),
Map.entry("dumpfile=", "dumpfile"),
Map.entry("gz=", "gz"),
Map.entry("histo", "-histo"),
Map.entry("clstats", "-clstats"),
Map.entry("finalizerinfo", "-finalizerinfo"));
Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);

boolean requestHeapdump = newArgMap.containsKey("binaryheap");
String dumpfile = newArgMap.get("dumpfile");
String gzLevel = newArgMap.get("gz");
String command = "-heap:format=b";
if (!requestHeapdump && (dumpfile != null)) {
throw new IllegalArgumentException("Unexpected argument: dumpfile");
}
if (requestHeapdump) {
if (dumpfile == null) {
newArgMap.put("-heap:format=b", null);
} else {
newArgMap.put("-heap:format=b,file=" + dumpfile, null);
if (gzLevel != null) {
command += ",gz=" + gzLevel;
}
if (dumpfile != null) {
command += ",file=" + dumpfile;
}
newArgMap.put(command, null);
}

newArgMap.remove("binaryheap");
newArgMap.remove("dumpfile");
newArgMap.remove("gz");
JMap.main(buildAttachArgs(newArgMap, false));
}

@@ -485,6 +493,8 @@ public static void main(String[] args) {
} catch (SAGetoptException e) {
System.err.println(e.getMessage());
toolHelp(args[0]);
// Exit with error status
System.exit(1);
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -50,16 +50,21 @@ public String getName() {
}

protected String getCommandFlags() {
return "-heap|-heap:format=b|-histo|-clstats|-finalizerinfo";
return "-heap|-heap:format=b[,gz=<1-9>][,file=<dumpfile>]|-heap:format=x[,file=<dumpfile>]|{-histo|-clstats|-finalizerinfo";
}

protected void printFlagsUsage() {
System.out.println(" <no option>\tto print same info as Solaris pmap");
System.out.println(" -heap\tto print java heap summary");
System.out.println(" -heap:format=b\tto dump java heap in hprof binary format");
System.out.println(" -histo\tto print histogram of java object heap");
System.out.println(" -clstats\tto print class loader statistics");
System.out.println(" -finalizerinfo\tto print information on objects awaiting finalization");
System.out.println(" <no option>\tTo print same info as Solaris pmap.");
System.out.println(" -heap\tTo print java heap summary.");
System.out.println(" -heap:format=b[,gz=<1-9>][,file=<dumpfile>] \tTo dump java heap in hprof binary format.");
System.out.println(" \tIf gz specified, the heap dump is written in gzipped format");
System.out.println(" \tusing the given compression level.");
System.err.println(" \t1 (recommended) is the fastest, 9 the strongest compression.");
System.out.println(" -heap:format=x[,file=<dumpfile>] \tTo dump java heap in GXL format.");
System.out.println(" \tPlease be aware that \"gz\" option is not valid for heap dump in GXL format.");
System.out.println(" -histo\tTo print histogram of java object heap.");
System.out.println(" -clstats\tTo print class loader statistics.");
System.out.println(" -finalizerinfo\tTo print information on objects awaiting finalization.");
super.printFlagsUsage();
}

@@ -72,6 +77,7 @@ protected void printFlagsUsage() {
public static final int MODE_FINALIZERINFO = 6;

private static String dumpfile = "heap.bin";
private static int gzLevel = 0;

public void run() {
Tool tool = null;
@@ -94,7 +100,7 @@ public void run() {
break;

case MODE_HEAP_GRAPH_HPROF_BIN:
writeHeapHprofBin(dumpfile);
writeHeapHprofBin(dumpfile, gzLevel);
return;

case MODE_HEAP_GRAPH_GXL:
@@ -151,6 +157,26 @@ public static void main(String[] args) {
System.exit(1);
}
dumpfile = keyValue[1];
} else if (keyValue[0].equals("gz")) {
if (mode == MODE_HEAP_GRAPH_GXL) {
System.err.println("\"gz\" option is not compatible with heap dump in GXL format");
System.exit(1);
}
if (keyValue.length == 1) {
System.err.println("Argument is expected for \"gz\"");
System.exit(1);
}
String level = keyValue[1];
try {
gzLevel = Integer.parseInt(level);
} catch (NumberFormatException e) {
System.err.println("\"gz\" option value not an integer ("+level+")");
System.exit(1);
}
if (gzLevel < 1 || gzLevel > 9) {
System.err.println("compression level out of range (1-9): " + level);
System.exit(1);
}
} else {
System.err.println("unknown option:" + keyValue[0]);

@@ -176,9 +202,17 @@ public static void main(String[] args) {
jmap.execute(args);
}

public boolean writeHeapHprofBin(String fileName) {
public boolean writeHeapHprofBin(String fileName, int gzLevel) {
try {
HeapGraphWriter hgw = new HeapHprofBinWriter();
HeapGraphWriter hgw;
if (gzLevel == 0) {
hgw = new HeapHprofBinWriter();
} else if (gzLevel >=1 && gzLevel <= 9) {
hgw = new HeapHprofBinWriter(gzLevel);
} else {
System.err.println("Illegal compression level: " + gzLevel);
return false;
}
hgw.write(fileName);
System.out.println("heap written to " + fileName);
return true;
@@ -188,7 +222,7 @@ public boolean writeHeapHprofBin(String fileName) {
}

public boolean writeHeapHprofBin() {
return writeHeapHprofBin("heap.bin");
return writeHeapHprofBin("heap.bin", -1);
}

private boolean writeHeapGXL(String fileName) {

0 comments on commit c54724d

Please sign in to comment.