Skip to content

Commit

Permalink
Let GC collect localSettings as soon as possible (#281)
Browse files Browse the repository at this point in the history
Motivation:

There is no need to hold a reference to the localSettings after we sent
it as we only do once.

Modifications:

- Null out localSettings as soon as possible to save memory

Result:

Less memory usage in long living connections
  • Loading branch information
normanmaurer authored Feb 3, 2024
1 parent 0d0e9cf commit f731f1d
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

import java.util.function.LongFunction;

import static io.netty.incubator.codec.http3.Http3SettingsFrame.HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY;

public final class Http3ClientConnectionHandler extends Http3ConnectionHandler {

private final LongFunction<ChannelHandler> pushStreamHandlerFactory;
Expand Down Expand Up @@ -69,8 +67,7 @@ void initBidirectionalStream(ChannelHandlerContext ctx, QuicStreamChannel channe

@Override
void initUnidirectionalStream(ChannelHandlerContext ctx, QuicStreamChannel streamChannel) {
final Long maxTableCapacity = remoteControlStreamHandler.localSettings()
.get(HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY);
final long maxTableCapacity = maxTableCapacity();
streamChannel.pipeline().addLast(
new Http3UnidirectionalStreamInboundClientHandler(codecFactory,
localControlStreamHandler, remoteControlStreamHandler,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public abstract class Http3ConnectionHandler extends ChannelInboundHandlerAdapte
final QpackEncoder qpackEncoder;
private boolean controlStreamCreationInProgress;

final long maxTableCapacity;

/**
* Create a new instance.
* @param server {@code true} if server-side, {@code false} otherwise.
Expand Down Expand Up @@ -71,7 +73,7 @@ public abstract class Http3ConnectionHandler extends ChannelInboundHandlerAdapte
// Just use the maximum value we can represent via a Long.
maxFieldSectionSize = Long.MAX_VALUE;
}
long maxTableCapacity = localSettings.getOrDefault(HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0);
this.maxTableCapacity = localSettings.getOrDefault(HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY, 0);
int maxBlockedStreams = toIntExact(localSettings.getOrDefault(HTTP3_SETTINGS_QPACK_BLOCKED_STREAMS, 0));
qpackDecoder = new QpackDecoder(maxTableCapacity, maxBlockedStreams);
qpackEncoder = new QpackEncoder();
Expand Down Expand Up @@ -193,6 +195,10 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
*/
abstract void initUnidirectionalStream(ChannelHandlerContext ctx, QuicStreamChannel streamChannel);

long maxTableCapacity() {
return maxTableCapacity;
}

/**
* Always returns {@code false} as it keeps state.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
final class Http3ControlStreamOutboundHandler
extends Http3FrameTypeDuplexValidationHandler<Http3ControlStreamFrame> {
private final boolean server;
private final Http3SettingsFrame localSettings;
private final ChannelHandler codec;
private Long sentMaxPushId;
private Long sendGoAwayId;
private Http3SettingsFrame localSettings;

Http3ControlStreamOutboundHandler(boolean server, Http3SettingsFrame localSettings, ChannelHandler codec) {
super(Http3ControlStreamFrame.class);
Expand All @@ -40,15 +40,6 @@ final class Http3ControlStreamOutboundHandler
this.codec = ObjectUtil.checkNotNull(codec, "codec");
}

/**
* Returns the local settings that were sent on the control stream.
*
* @return the local {@link Http3SettingsFrame}.
*/
Http3SettingsFrame localSettings() {
return localSettings;
}

/**
* Returns the last id that was sent in a MAX_PUSH_ID frame or {@code null} if none was sent yet.
*
Expand All @@ -69,8 +60,13 @@ public void channelActive(ChannelHandlerContext ctx) {
// Add the encoder and decoder in the pipeline so we can handle Http3Frames. This needs to happen after
// we did write the type via a ByteBuf.
ctx.pipeline().addFirst(codec);

assert localSettings != null;
// If writing of the local settings fails let's just teardown the connection.
closeOnFailure(ctx.writeAndFlush(DefaultHttp3SettingsFrame.copyOf(localSettings)));
closeOnFailure(ctx.writeAndFlush(localSettings));

// Let the GC collect localSettings.
localSettings = null;

ctx.fireChannelActive();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ void initBidirectionalStream(ChannelHandlerContext ctx, QuicStreamChannel stream

@Override
void initUnidirectionalStream(ChannelHandlerContext ctx, QuicStreamChannel streamChannel) {
final Long maxTableCapacity = remoteControlStreamHandler.localSettings()
.get(HTTP3_SETTINGS_QPACK_MAX_TABLE_CAPACITY);
final long maxTableCapacity = maxTableCapacity();
streamChannel.pipeline().addLast(
new Http3UnidirectionalStreamInboundServerHandler(codecFactory,
localControlStreamHandler, remoteControlStreamHandler,
Expand Down

0 comments on commit f731f1d

Please sign in to comment.