Environment: linux java: java8 spring: spring-boot-starter-webflux 2.3.2.RELEASE reactor-netty I was using write response in this way, Will there be a memory leak?
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain webFilterChain) {
// here is io thread
return webFilterChain.filter(exchange).then(Mono.defer(() -> {
// here is business thread
// business code
result = outputstream
DataBuffer dataBuffer;
try {
dataBuffer = exchange.getResponse().bufferFactory().wrap(result.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new SystemException("write-error",e);
}
return response.writeWith(Mono.just(dataBuffer));
}));
}
For there was used by netty and netty's pooled buffer should be created and be released in the same thread or there will be a memory leak.
To avoid the leak, I study the source code
public final Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
// For Mono we can avoid ChannelSendOperator and Reactor Netty is more optimized for Mono.
// We must resolve value first however, for a chance to handle potential error.
if (body instanceof Mono) {
return ((Mono<? extends DataBuffer>) body)
.flatMap(buffer -> doCommit(() ->
writeWithInternal(Mono.fromCallable(() -> buffer)
.doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release))))
.doOnError(t -> getHeaders().clearContentHeaders());
}
else {
return new ChannelSendOperator<>(body, inner -> doCommit(() -> writeWithInternal(inner)))
.doOnError(t -> getHeaders().clearContentHeaders());
}
would you tell me when the doOnDiscard will work and the thread of DataBufferUtils::release is the same as bufferFactory.wrap?
Comment From: rstoyanchev
Thanks for getting in touch, but it feels like this is a question that would be better suited to Stack Overflow. As mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements. Feel free to update this issue with a link to the re-posted question (so that other people can find it) or add some more details if you feel this is a genuine bug.
Comment From: rstoyanchev
As an additional comment, in the call to exchange
it seems you are ignoring the ClientResponse
. That can certainly cause a leak of the response body is not empty. Please, review this recent documentation update #26819.
Comment From: vector20240801
Is it nesscessary to release buffer after sending it? I assume the buffer will be realsed in Netty automatically.
DataBuffer dataBuffer;
String ret = "string from other logic"
try {
dataBuffer = exchange.getResponse().bufferFactory().wrap(ret.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new SystemException("write-error",e);
}
return serverResponse.writeWith(Mono.just(dataBuffer)).doFinally(signalType -> {
DataBufferUtils.release(dataBuffer);
});
and please told me a bit about the process in org.springframework.http.server.reactive.AbstractServerHttpResponse#writeWith when will doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release)) work?
Comment From: vector20240801
May be there will not be a memory leak ? I have seen exchange.getResponse().bufferFactory().wrap will just return a unpooledheaped buffer, Is there no need to release? And I really want to know when will the doOnDiscard(PooledDataBuffer.class, DataBufferUtils::release)) work in org.springframework.http.server.reactive.AbstractServerHttpResponse#writeWith