Skip to content

Commit 461c5fc

Browse files
Lin ZangPaul Hohensee
authored andcommitted
8256450: Add gz option to jmap to write a gzipped heap dump
Reviewed-by: cjplummer, sspitsyn, phh
1 parent dee79d6 commit 461c5fc

File tree

3 files changed

+56
-9
lines changed

3 files changed

+56
-9
lines changed

src/hotspot/share/services/attachListener.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ static jint jcmd(AttachOperation* op, outputStream* out) {
218218
// Input arguments :-
219219
// arg0: Name of the dump file
220220
// arg1: "-live" or "-all"
221+
// arg2: Compress level
221222
jint dump_heap(AttachOperation* op, outputStream* out) {
222223
const char* path = op->arg(0);
223224
if (path == NULL || path[0] == '\0') {
@@ -233,11 +234,22 @@ jint dump_heap(AttachOperation* op, outputStream* out) {
233234
live_objects_only = strcmp(arg1, "-live") == 0;
234235
}
235236

237+
const char* num_str = op->arg(2);
238+
uintx level = 0;
239+
if (num_str != NULL && num_str[0] != '\0') {
240+
if (!Arguments::parse_uintx(num_str, &level, 0)) {
241+
out->print_cr("Invalid compress level: [%s]", num_str);
242+
return JNI_ERR;
243+
} else if (level < 1 || level > 9) {
244+
out->print_cr("Compression level out of range (1-9): " UINTX_FORMAT, level);
245+
return JNI_ERR;
246+
}
247+
}
236248
// Request a full GC before heap dump if live_objects_only = true
237249
// This helps reduces the amount of unreachable objects in the dump
238250
// and makes it easier to browse.
239251
HeapDumper dumper(live_objects_only /* request GC */);
240-
dumper.dump(op->arg(0), out);
252+
dumper.dump(op->arg(0), out, (int)level);
241253
}
242254
return JNI_OK;
243255
}

src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ private static void dump(String pid, String options)
209209
String subopts[] = options.split(",");
210210
String filename = null;
211211
String liveopt = "-all";
212+
String compress_level = null;
212213

213214
for (int i = 0; i < subopts.length; i++) {
214215
String subopt = subopts[i];
@@ -224,6 +225,12 @@ private static void dump(String pid, String options)
224225
}
225226
} else if (subopt.equals("format=b")) {
226227
// ignore format (not needed at this time)
228+
} else if (subopt.startsWith("gz=")) {
229+
compress_level = subopt.substring("gz=".length());
230+
if (compress_level == null) {
231+
System.err.println("Fail: no number provided in option: '" + subopt + "'");
232+
usage(1);
233+
}
227234
} else {
228235
System.err.println("Fail: invalid option: '" + subopt + "'");
229236
usage(1);
@@ -238,7 +245,7 @@ private static void dump(String pid, String options)
238245
System.out.flush();
239246

240247
// dumpHeap is not the same as jcmd GC.heap_dump
241-
executeCommandForPid(pid, "dumpheap", filename, liveopt);
248+
executeCommandForPid(pid, "dumpheap", filename, liveopt, compress_level);
242249
}
243250

244251
private static void checkForUnsupportedOptions(String[] args) {
@@ -303,6 +310,8 @@ private static void usage(int exit) {
303310
System.err.println(" all dump all objects in the heap (default if one of \"live\" or \"all\" is not specified)");
304311
System.err.println(" format=b binary format");
305312
System.err.println(" file=<file> dump heap to <file>");
313+
System.err.println(" gz=<number> If specified, the heap dump is written in gzipped format using the given compression level.");
314+
System.err.println(" 1 (recommended) is the fastest, 9 the strongest compression.");
306315
System.err.println("");
307316
System.err.println(" Example: jmap -dump:live,format=b,file=heap.bin <pid>");
308317
System.err.println("");

test/jdk/sun/tools/jmap/BasicJMapTest.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,13 @@
2222
*/
2323

2424
import static jdk.test.lib.Asserts.assertTrue;
25+
import static jdk.test.lib.Asserts.assertFalse;
2526
import static jdk.test.lib.Asserts.fail;
2627

2728
import java.io.File;
29+
import java.nio.file.Files;
2830
import java.util.Arrays;
31+
import java.util.List;
2932

3033
import jdk.test.lib.JDKToolLauncher;
3134
import jdk.test.lib.Utils;
@@ -114,6 +117,7 @@ public static void main(String[] args) throws Exception {
114117
testDump();
115118
testDumpLive();
116119
testDumpAll();
120+
testDumpCompressed();
117121
}
118122

119123
private static void testHisto() throws Exception {
@@ -211,20 +215,25 @@ private static void testClstats() throws Exception {
211215
}
212216

213217
private static void testDump() throws Exception {
214-
dump(false, false);
218+
dump(false, false, false);
215219
}
216220

217221
private static void testDumpLive() throws Exception {
218-
dump(true, false);
222+
dump(true, false, false);
219223
}
220224

221225
private static void testDumpAll() throws Exception {
222-
dump(false, true);
226+
dump(false, true, false);
223227
}
224228

225-
private static void dump(boolean live, boolean explicitAll) throws Exception {
229+
private static void testDumpCompressed() throws Exception {
230+
dump(true, false, true);
231+
}
232+
233+
private static void dump(boolean live, boolean explicitAll, boolean compressed) throws Exception {
226234
String liveArg = "";
227235
String fileArg = "";
236+
String compressArg = "";
228237
String allArgs = "-dump:";
229238

230239
if (live && explicitAll) {
@@ -237,14 +246,20 @@ private static void dump(boolean live, boolean explicitAll) throws Exception {
237246
liveArg = "all,";
238247
}
239248

240-
File file = new File("jmap.dump" + System.currentTimeMillis() + ".hprof");
249+
String filePath = "jmap.dump" + System.currentTimeMillis() + ".hprof";
250+
if (compressed) {
251+
compressArg = "gz=1,";
252+
filePath = filePath + ".gz";
253+
}
254+
255+
File file = new File(filePath);
241256
if (file.exists()) {
242257
file.delete();
243258
}
244259
fileArg = "file=" + file.getName();
245260

246261
OutputAnalyzer output;
247-
allArgs = allArgs + liveArg + "format=b," + fileArg;
262+
allArgs = allArgs + liveArg + compressArg + "format=b," + fileArg;
248263
output = jmap(allArgs);
249264
output.shouldHaveExitValue(0);
250265
output.shouldContain("Heap dump file created");
@@ -255,7 +270,18 @@ private static void dump(boolean live, boolean explicitAll) throws Exception {
255270
private static void verifyDumpFile(File dump) {
256271
assertTrue(dump.exists() && dump.isFile(), "Could not create dump file " + dump.getAbsolutePath());
257272
try {
258-
HprofParser.parse(dump);
273+
File out = HprofParser.parse(dump);
274+
275+
assertTrue(out != null && out.exists() && out.isFile(),
276+
"Could not find hprof parser output file");
277+
List<String> lines = Files.readAllLines(out.toPath());
278+
assertTrue(lines.size() > 0, "hprof parser output file is empty");
279+
for (String line : lines) {
280+
assertFalse(line.matches(".*WARNING(?!.*Failed to resolve " +
281+
"object.*constantPoolOop.*).*"));
282+
}
283+
284+
out.delete();
259285
} catch (Exception e) {
260286
e.printStackTrace();
261287
fail("Could not parse dump file " + dump.getAbsolutePath());

0 commit comments

Comments
 (0)