• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20245

17 Apr 2026 02:24PM UTC coverage: 88.788% (-0.02%) from 88.811%
#20245

push

github

web-flow
core: Reduce per-stream idle memory by 20%

Metadata was accidentally being retained after the start of the call.
That can be an overwhelming percentage of memory for an idle RPC; don't
do that. The other changes are considerably smaller, but I happened to
notice them and the changes are straight-forward without magic numbers
(e.g., there's many arrays that could be tuned).

The regular interop server uses 4600 bytes per full duplex stream while
idle, but much of that is Census recorded events hanging around. Keeping
the Census integration but removing the Census impl (so a noop is used)
drops that to 3000 bytes. This change brings that down to ~2450 bytes
(which is still including stuff from TestServiceImpl). But there's very
little Metadata in the interop tests, so absolute real-life savings
would be much higher (but relative real-life savings may be lower,
because the application will often have more state).

The measurements were captured using a modified
timeout_on_sleeping_server client that had 100,000 concurrent full
duplex calls on one connection.

36015 of 40563 relevant lines covered (88.79%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.88
/../netty/src/main/java/io/grpc/netty/ClientTransportLifecycleManager.java
1
/*
2
 * Copyright 2016 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.netty;
18

19
import com.google.errorprone.annotations.CanIgnoreReturnValue;
20
import io.grpc.Attributes;
21
import io.grpc.Status;
22
import io.grpc.internal.DisconnectError;
23
import io.grpc.internal.ManagedClientTransport;
24

25
/** Maintainer of transport lifecycle status. */
26
final class ClientTransportLifecycleManager {
27
  private final ManagedClientTransport.Listener listener;
28
  private boolean transportReady;
29
  private boolean transportShutdown;
30
  private boolean transportInUse;
31
  /** null iff !transportShutdown. */
32
  private Status shutdownStatus;
33
  /** null iff !transportShutdown. */
34
  private boolean transportTerminated;
35

36
  public ClientTransportLifecycleManager(ManagedClientTransport.Listener listener) {
1✔
37
    this.listener = listener;
1✔
38
  }
1✔
39

40
  public Attributes filterAttributes(Attributes attributes) {
41
    if (transportReady || transportShutdown) {
1✔
42
      return attributes;
×
43
    }
44
    return listener.filterTransport(attributes);
1✔
45
  }
46

47
  public void notifyReady() {
48
    if (transportReady || transportShutdown) {
1✔
49
      return;
×
50
    }
51
    transportReady = true;
1✔
52
    listener.transportReady();
1✔
53
  }
1✔
54

55
  /**
56
   * Marks transport as shutdown, but does not set the error status. This must eventually be
57
   * followed by a call to notifyShutdown.
58
   */
59
  public void notifyGracefulShutdown(Status s, DisconnectError disconnectError) {
60
    if (transportShutdown) {
1✔
61
      return;
1✔
62
    }
63
    transportShutdown = true;
1✔
64
    listener.transportShutdown(s, disconnectError);
1✔
65
  }
1✔
66

67
  /** Returns {@code true} if was the first shutdown. */
68
  @CanIgnoreReturnValue
69
  public boolean notifyShutdown(Status s, DisconnectError disconnectError) {
70
    notifyGracefulShutdown(s, disconnectError);
1✔
71
    if (shutdownStatus != null) {
1✔
72
      return false;
1✔
73
    }
74
    shutdownStatus = s;
1✔
75
    return true;
1✔
76
  }
77

78
  public void notifyInUse(boolean inUse) {
79
    if (inUse == transportInUse) {
1✔
80
      return;
×
81
    }
82
    transportInUse = inUse;
1✔
83
    listener.transportInUse(inUse);
1✔
84
  }
1✔
85

86
  public void notifyTerminated(Status s, DisconnectError disconnectError) {
87
    if (transportTerminated) {
1✔
88
      return;
×
89
    }
90
    transportTerminated = true;
1✔
91
    notifyShutdown(s, disconnectError);
1✔
92
    listener.transportTerminated();
1✔
93
  }
1✔
94

95
  public Status getShutdownStatus() {
96
    return shutdownStatus;
1✔
97
  }
98

99
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc