Skip to content

Commit 3c66485

Browse files
committedDec 16, 2020
8257906: JFR: RecordingStream leaks memory
Reviewed-by: mgronlun
1 parent 0c8cc2c commit 3c66485

File tree

4 files changed

+54
-3
lines changed

4 files changed

+54
-3
lines changed
 

‎src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordingStream.java

+40-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import jdk.jfr.internal.SecuritySupport;
4646
import jdk.jfr.internal.Utils;
4747
import jdk.jfr.internal.consumer.EventDirectoryStream;
48-
import jdk.jfr.internal.consumer.JdkJfrConsumer;
4948

5049
/**
5150
* A recording stream produces events from the current JVM (Java Virtual
@@ -68,9 +67,27 @@
6867
*/
6968
public final class RecordingStream implements AutoCloseable, EventStream {
7069

70+
final static class ChunkConsumer implements Consumer<Long> {
71+
72+
private final Recording recording;
73+
74+
ChunkConsumer(Recording recording) {
75+
this.recording = recording;
76+
}
77+
78+
@Override
79+
public void accept(Long endNanos) {
80+
Instant t = Utils.epochNanosToInstant(endNanos);
81+
PlatformRecording p = PrivateAccess.getInstance().getPlatformRecording(recording);
82+
p.removeBefore(t);
83+
}
84+
}
85+
7186
private final Recording recording;
7287
private final Instant creationTime;
7388
private final EventDirectoryStream directoryStream;
89+
private long maxSize;
90+
private Duration maxAge;
7491

7592
/**
7693
* Creates an event stream for the current JVM (Java Virtual Machine).
@@ -247,7 +264,11 @@ public EventSettings disable(Class<? extends Event> eventClass) {
247264
* state
248265
*/
249266
public void setMaxAge(Duration maxAge) {
250-
recording.setMaxAge(maxAge);
267+
synchronized (directoryStream) {
268+
recording.setMaxAge(maxAge);
269+
this.maxAge = maxAge;
270+
updateOnCompleteHandler();
271+
}
251272
}
252273

253274
/**
@@ -270,7 +291,11 @@ public void setMaxAge(Duration maxAge) {
270291
* @throws IllegalStateException if the recording is in {@code CLOSED} state
271292
*/
272293
public void setMaxSize(long maxSize) {
273-
recording.setMaxSize(maxSize);
294+
synchronized (directoryStream) {
295+
recording.setMaxSize(maxSize);
296+
this.maxSize = maxSize;
297+
updateOnCompleteHandler();
298+
}
274299
}
275300

276301
@Override
@@ -320,6 +345,7 @@ public void onError(Consumer<Throwable> action) {
320345

321346
@Override
322347
public void close() {
348+
directoryStream.setChunkCompleteHandler(null);
323349
recording.close();
324350
directoryStream.close();
325351
}
@@ -333,6 +359,7 @@ public boolean remove(Object action) {
333359
public void start() {
334360
PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
335361
long startNanos = pr.start();
362+
updateOnCompleteHandler();
336363
directoryStream.start(startNanos);
337364
}
338365

@@ -363,6 +390,7 @@ public void start() {
363390
public void startAsync() {
364391
PlatformRecording pr = PrivateAccess.getInstance().getPlatformRecording(recording);
365392
long startNanos = pr.start();
393+
updateOnCompleteHandler();
366394
directoryStream.startAsync(startNanos);
367395
}
368396

@@ -380,4 +408,13 @@ public void awaitTermination() throws InterruptedException {
380408
public void onMetadata(Consumer<MetadataEvent> action) {
381409
directoryStream.onMetadata(action);
382410
}
411+
412+
private void updateOnCompleteHandler() {
413+
if (maxAge != null || maxSize != 0) {
414+
// User has set a chunk removal policy
415+
directoryStream.setChunkCompleteHandler(null);
416+
} else {
417+
directoryStream.setChunkCompleteHandler(new ChunkConsumer(recording));
418+
}
419+
}
383420
}

‎src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkParser.java

+12
Original file line numberDiff line numberDiff line change
@@ -488,4 +488,16 @@ public void setStaleMetadata(boolean stale) {
488488
public boolean hasStaleMetadata() {
489489
return staleMetadata;
490490
}
491+
492+
public void resetCache() {
493+
LongMap<Parser> ps = this.parsers;
494+
if (ps != null) {
495+
ps.forEach(p -> {
496+
if (p instanceof EventParser) {
497+
EventParser ep = (EventParser) p;
498+
ep.resetCache();
499+
}
500+
});
501+
}
502+
}
491503
}

‎src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventDirectoryStream.java

+1
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ protected void processRecursionSafe() throws IOException {
159159
} else {
160160
processUnordered(disp);
161161
}
162+
currentParser.resetCache();
162163
if (currentParser.getStartNanos() + currentParser.getChunkDuration() > filterEnd) {
163164
close();
164165
return;

‎src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventFileStream.java

+1
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ protected void process() throws IOException {
102102
} else {
103103
processUnordered(disp);
104104
}
105+
currentParser.resetCache();
105106
if (isClosed() || currentParser.isLastChunk()) {
106107
return;
107108
}

0 commit comments

Comments
 (0)
Please sign in to comment.