Unmanaged resource clean-up

gRPC-based APIs and channels

Clients are thread-safe, and in general we recommend using a single instance across a whole application unless you particularly need different settings for some clients.

gRPC uses the concept of a channel between your application and the service implementing an API. This consists of a network connection and some unmanaged resources which handle its status and multiplex the requests and responses on it.

Most of the time, you don't need to worry about cleaning up the unmanaged resources from the C# client libraries. If you use multiple client instances created in an entirely-default way, a single gRPC channel will be shared between all instances.

If you want to handle this explicitly, you can do so by creating channels yourself and shutting them down in an orderly fashion. For slightly less control (but a simpler life) you can let the client libraries create channels themselves as necessary, and shut them down explicitly using the static ShutDownDefaultChannelsAsync method which each client class exposes. (For example, PublisherServiceApiClient.ShutDownDefaultChannelsAsync() and SubscriberServiceApiClient.ShutDownDefaultChannelsAsync().)

Finally, gRPC provides an environment-wide shutdown method of GrpcEnvironment.ShutdownChannelsAsync().

In all of these cases, it's entirely feasible to create more channels (implicitly or explicitly) after shutting others down... it will just require a new network connection to be opened.

If you do not shut down the channels explicitly, they will be closed automatically when either the application domain is unloaded, or the process exits. For most applications, this is perfectly adequate; explicit shutdown is only required when your application needs to ensure that it has handled all requests appropriately before exiting.

For more information, see the client lifecycle documentation

Streaming calls

Streaming RPCs should be disposed, and ideally all responses read before disposal. See the streaming RPCs documentation for more details.

REST-based APIs

Summary: Use a single client if you can. Clients are threads-safe, so in most situations you can use a single client for the whole application. If you have to create multiple clients at a high frequency, dispose of them when you're done.

Just as a reminder, Google Cloud Client Libraries for .NET has three libraries for REST-based APIs:

  • Google.Cloud.Storage.V1 (StorageClient)
  • Google.Cloud.BigQuery.V2 (BigQueryClient)
  • Google.Cloud.Translation.V2 (TranslationClient, AdvancedTranslationClient)

In November 2017, these client classes were changed to implement the IDisposable interface. The Dispose method simply disposes of the underlying service object, which in turn disposes of the underlying HttpClient.

There are three broad usage scenarios to consider:

  • A single long-lived client object (or perhaps a limited set, e.g. using different credentials) used for many operations.
  • A new client used for each set of operations, e.g. a new client created for each incoming request on a web site, but with relatively low-frequency use.
  • A new client created for each set of operations, with high-frequency use.

The ability to dispose of the client really only affects the last of these scenarios. The way that HttpClient works has two downsides when new clients are created frequently:

  • Connections to the API server (e.g. the Storage API server) can take a long time to close. This can cause problems if you're running in an environment with a limited number of available connections.
  • Buffers within HttpClient can consume memory for longer than is desirable.

In many cases these don't actually cause problems - if you don't reach your connection limit, and the garbage collector is collecting the HttpClient buffers fast enough to keep your memory usage low, you're fine. Likewise if you only ever create a limited set of client objects, you shouldn't run into issues.

In other cases, where (for whatever reason) you really want to create a lot of client objects in quick succession, it's prudent to dispose of the clients when you're done with them. Now that the client classes implement IDisposable, you can simply use using statements in the normal way.