【发布时间】:2018-05-15 14:54:17
【问题描述】:
我正在使用 gRPC 开发 .net core 2.0 应用程序并发现一个问题:删除对我的 gRPC 客户端类实例的引用后,仍然存在使用资源(内存和处理器)的通道。 示例代码:
public class MyClient : ClientBase
{
public MyClient(Channel channel) : base(channel)
{
}
}
internal class Program
{
private static void Main(string[] args)
{
var list = new List<MyClient>();
for (var i = 0; i < 10000; i++)
{
Console.WriteLine($"Creating {i} instance");
list.Add(new MyClient(new Channel("127.0.0.1:61783", ChannelCredentials.Insecure)));
}
Console.WriteLine("press enter to list = null");
Console.ReadLine();
list = null;
Console.WriteLine("press enter to GC.Collect();");
Console.ReadLine();
GC.Collect();
Console.WriteLine("press enter to exit");
Console.ReadLine();
}
}
如果你运行示例,你会看到这个应用程序使用了 10%(在我的 PC 上)。即使在 list = null 和 GC.Collect()
之后我认为原因是 ClientBase 不要调用 Channel.ShutdownAsync()。
所以问题是:
解决问题的更好方法是什么?
附言实际上我使用的是“由协议缓冲区编译器生成的”客户端
Client: Grpc.Core.ClientBase<TDto>
我无法在生成的类中显式更改终结器
【问题讨论】:
-
你为什么不自己关闭频道?
-
我不确定这是不是最好的解决方案:我认为使用 using{} 或在 finilize() 方法处理资源的最佳做法...
-
您正在使用不打算像这样使用的第三方库(没有实现
IDisposable,甚至是通道),因此在这种情况下,最好的方法是在您使用时显式关闭通道与它们一起完成,而不是依赖任何东西(如垃圾收集器)为你做这件事。好吧,最好不要依赖 GC 来释放一些你无论如何都可以自己释放的资源。 -
@TimurLemeshko 让您的客户端实现
IDisposable并在Dispose方法中调用base.Channel.ShutdownAsync()。这将允许您现在在客户端上调用 Dispose 并释放资源或将它们包装在using中,以便在它们超出范围时为您完成 -
@Nkosi 那里没有
base.Channel。但即使有 -ShutdownAsync()返回Task,所以只在 dispose 中执行ShutdownAsync()似乎是不对的(并且执行ShutdownAsync().Wait()似乎也不正确)。
标签: c# memory-leaks asp.net-core grpc