下午好。
我遇到内存泄漏问题,我想我知道发生这种情况的重点,但我不知道我需要做些什么来解决它!希望你们能再次救我。
我真的试图谷歌(很多),但我发现或测试的结果都没有实际发挥作用。
我使用了大量功能,但我必须遵循客户的IT部门的一些架构规则,因此无法考虑此主题,例如不要例如,使用Ninject或不使用WCF。我能做的(也许我需要做的)是改变它们的实施方式。
那就是说,让我们去看炸弹。
在我的项目中,表示层托管在一个服务器中,WCF服务及其所有依赖项(域,存储库等)都在另一个服务器中。
问题出在WCF服务器上,此服务器会增加从演示到服务的每个请求的内存使用量,并且在服务器内存达到限制之前不会释放此内存,并且需要重新启动服务器,或重新启动IIS应用程序池。
以下使用的技术:
域模型,WCF,带Web API的MVC4,MVC和WCF中的Ninject 3.2,用于从域到dto和反向映射的AutoMapper,Repository和NHibernate。
我已经检查了Repository和NHibernate层,他们正确地处理了他们的对象。
我正在使用Ninject在演示文稿中注入WCF,如App_Start中所示:
public class NinjectConfiguration
{
public void Configure(IKernel container)
{
AddBindings(container);
var resolver = new NinjectDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = resolver;
}
private void AddBindings(IKernel container)
{
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>());
// ...
}
public TService CreateChannel<TService>() where TService : class
{
var factory = new ChannelFactory<TService>(string.Empty);
factory.Open();
return factory.CreateChannel();
}
}
演示文稿Web.Config端点配置:
<system.serviceModel>
<client>
<endpoint address="http://MyEndPoint/PersonService.svc" binding="wsHttpBinding" bindingConfiguration="BindClientConfig" contract="MyContract.IPersonService" />
</client>
<bindings>
<wsHttpBinding>
<binding name="BindClientConfig" maxReceivedMessageSize="2147483647" sendTimeout="00:01:00"></binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
我的WEBApi配置:
public class PersonController : ApiController
{
IPesrsonService _personService;
public PersonController(IPesrsonService personParam) { ... }
//Gets, Post, Put, Delete here and functional
protected override void Dispose(bool disposing)
{
if (_personService != null)
{
_personService.Dispose(); //This point is reached
}
base.Dispose(disposing);
}
}
我的WCF Dispose(合同实现了IDisposable):
public class PersonService : IPersonService
{
private IPersonDomain _personDomain;
public PersonService(IPersonDomain personDomainParam) { ... }
//...
protected virtual void Dispose(bool disposing) { ... }
public void Dispose()
{
Dispose(true); //This point is NEVER reached
GC.SuppressFinalize(this);
}
}
理论上,WebAPI中的_personService.Dispose必须从WCF调用Dispose,但永远不会到达此Dispose WCF。我可以从WCF到达任何其他方法,但是Dispose,我不能。
我的猜测是我在Ninject配置上遗漏了一些东西,造成了这个非管理的漏洞。
表示层似乎实际上并没有关闭与WCF的连接,这样就让端点永远在通信的另一端(WCF服务器)打开,并在那里保留分配的内存。
我已经尝试过如下更改NinjectConfiguration,但没有成功:
private void AddBindings(IKernel container)
{
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>());
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).OnDeactivation(CloseServiceConnection);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).OnDeactivation(CloseServiceConnection<IPersonService>);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current).OnDeactivation(CloseServiceConnection);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => HttpContext.Current).OnDeactivation(CloseServiceConnection<IPersonService>);
container.Bind<IPersonService>().ToMethod(ctx => CreateChannel<IPersonService>()).InScope(ctx => OperationContext.Current).OnDeactivation(CloseServiceConnection<IPersonService>);
}
public static void CloseServiceConnection<T>(T service)
{
(service as IDisposable).Dispose();
}
也许NinjectConfiguration类的CreateChannel可以用其他方式创建,所以我可以调用channel.Close(),但我不知道怎么做。
但这一切只是猜测。你发布的所有内容我都会尝试。
感谢您的帮助,非常感谢您的时间。
Elek Guidolin
答案 0 :(得分:1)
我建议为每个服务调用创建一个新的频道工厂可能是问题的一部分。创建一次,缓存它,然后重复使用它以根据需要创建新通道。如果由于某种原因每次都需要创建一个新的,请记住以后再处理它。
答案 1 :(得分:0)
我有同样的问题,除非您的WCF合同继承自IDisposable,否则永远不会调用Dispose()。
每次创建一个新的ChannelFactory都没问题,但它占用了不需要的CPU周期。我试图缓存一次ChannelFactory,但这导致Ninject无法在HTTP请求结束时删除该对象。
我通过采用我发现的一些代码来处理这个问题,这些代码在使用语句(使用Castle)中包装对WCF客户端的调用,并且还缓存了ChannelFactory,因为这非常耗费时间。有关更多信息,请访问:
https://adrianhesketh.wordpress.com/2015/03/17/wcf-client-proxy-creation-performance-with-ninject/
解决方案的来源是此博客:https://luisfsgoncalves.wordpress.com/2012/02/28/mixin-up-ninject-castle-dynamic-proxy-and-wcf-part-iii/
其他海报已经注意到一个好的方法是将Func传入您的MVC Web应用程序,因为这可以防止在可能实际不需要的情况下由DI框架创建IPersonService的实例。