原文地址:

http://nexussharp.wordpress.com/2012/04/21/castle-windsor-avoid-memory-leaks-by-learning-the-underlying-mechanics/

CASTLE WINDSOR: AVOID MEMORY LEAKS BY LEARNING THE UNDERLYING MECHANICS

Lifestyles

In am not going to explain all the different lifestyles Windsor has as you could read up on them on the Castle Wiki but for the sake of completeness I will list the most important ones and explain them in my own words

  • Singleton: This is actually the default lifestyle, means there will be only 1 instance of that class in your container (think static)
  • PerThread: There will only 1 instance per thread (think threadstatic)
  • PerWebRequest: There will only be 1 instance per web request
  • Pooled: There will be multiple instances of the same object but in a pool with a minimum pool size and a maximum pool size
  • Transient: Each time an instance is requested windsor will initialize a new one

Service Locator

Part of ASP.NET MVC 3 is the IDependencyResolver interface which is basically the contract of the service locator pattern (described by Martin Fowler here) or better said anti pattern!

If you are using Castle Windsor combined with service location you can get a lot of memory issues basically because the contract has no method for releasing your services/components.

When you are using Windsor you should always try to avoid getting an instance from the container yourself and when you have to, remember to always release the component after using it !

IComponent component = container.Resolve();
component.Act();
container.Release(component);

But why is that? Why do we need to release our components that we ask for explicitly?

Release Policy

Again this is explained very detailed on the Castle Wiki but i will list the important ones.

  • LifecycledComponentsReleasePolicy (default)
  • NoTrackingReleasePolicy

By default Windsor will use LifecycledComponentsReleasePolicy which keeps track of all components that were created, and upon releasing them, invokes all their decommission lifecycle steps.

In other words your garbage collector will not be able to cleanup if your container still tracks your component. Which will result into memory leaks. Now i’ve seen many posts and questions on the web about this where people are advising to use the NoTrackingReleasePolicy, don’t because the default release policy is actually a good thing!

Lifecycle concerns

See Castle Wiki for a detailed description.

  • Creation – commission concerns : everything happening within container.Resolve or similar method
  • destruction – decommission concerns : everything happening within and/or aftercontainer.ReleaseComponent.

A good example of a decommission concern is when your component implements IDisposable, the container will automatically recognize this as a decommission concern.

But why and exactly when does the memory leak happen?

If you look back on the lifestyles you will see that there are lifestyles, where the begin and end of the lifetime of the component is clear:

  • Singleton : the life of the component start at commission (resolve) and ends when the container is disposed
  • PerThread : the life of the component ends when the thread ends
  • PerWebRequest : …

But what about Transient and Pooled ? Especially with these you gotta watch out !

public interface IComponent { }

public class MyComponent: IComponent { }

public interface IDisposableComponent: IComponent,IDisposable
{
bool IsDisposed { get; }
} public class MyDisposableComponent: IDisposableComponent
{
public bool IsDisposed { get; private set; } public void Dispose()
{
IsDisposed = true;
}
} public interface IService
{
IDisposableComponent Component { get; }
} public class MyServiceUsingComponent: IService
{
public IDisposableComponent Component { get; private set; } public MyServiceUsingComponent(IDisposableComponent component)
{
Component = component;
}
}

What happens if we resolve a transient

 container.Register(Component.For<IComponent>()
.ImplementedBy<MyComponent>()
.LifestyleTransient());
var component=container.Resolve<IComponent>();
Assert.IsFalse(container.Kernel.ReleasePolicy.HasTrack(component));

So this actually means that Windsor is not tracking the component, which means the garbage collector will be able to clean up this instance.

What happens if we resolve a transient with a decommission concern for instance IDisposable

container.Register(Component.For<IDisposableComponent>()
.ImplementedBy<MyDisposableComponent>()
.LifeStyle.Transient);
var component = container.Resolve<IDisposableComponent>();
Assert.IsTrue(container.Kernel.ReleasePolicy.HasTrack(component));

So if we don’t release the component after using it, the garbage collector will not be able to pick it up as Windsor is still referencing it and your dispose method will never get invoked !

What happens if we resolve a transient component that is dependent on another transient component with a decommission concern ?

container.Register(Component.For<IDisposableComponent>()
.ImplementedBy<MyDisposableComponent>()
.LifeStyle.Transient);
container.Register(Component.For<IService>()
.ImplementedBy<MyServiceUsingComponent>()
.LifeStyle.Transient);
var service = container.Resolve<IService>();
Assert.IsTrue(container.Kernel.ReleasePolicy.HasTrack(service));

The tracking will propagate onto the parent service so again if we don’t release the service after using it, we will get a memory leak !

Always release after you are done

Container.Register(Component.For<IDisposableComponent>()
.ImplementedBy<MyDisposableComponent>()
.LifeStyle.Transient);
var component = Container.Resolve<IDisposableComponent>();
Container.Release(component);
Assert.IsTrue(component.IsDisposed);

Why does Windsor track components with a decommission concern ?

At the end of the lifetime of the component, either trough a implicit (Component or Component dependent on ends life) or explicit release (trough a container.Release), Windsor will execute all decommission steps. For instance when your component implements IDisposable, Windsor will call the Dispose method.

Conclusion

The ‘LifecycledComponentsReleasePolicy’ is great because it will track your components that have no real end of life defined and will cleanup after you. But especially be aware if you have a singleton component taking in a transient dependency with a decommission concern, because even if you release your singleton component after using it, it will not release the transient dependency immediatly, it will have to wait until your singleton’s life ends!

Because the real releasing (think disposing) of your transient dependency will happen at the end the life of the singleton component, most of the time when your application stops, only then will the container release the reference to the transient dependency and eventually call the dispose method. And even then this is just 1 instance of that transient component, so that will not cause a memory issue.

But in a real world scenario where you follow the advice of if you have to resolve yourself, you release after using the component. You will have no memory leaks !!!

So bye bye Service Locator without a release method and hello really powerfull IOC !!

避免Castle Windsor引起的内存泄露的更多相关文章

  1. MEF等Ioc框架引起内存泄露-PartCreationPolicy

    对象的创建可以使用new,也可以使用IOC架如:castle.MEF等,IOC创建的对象的生命周期,可能IOC负责管理,使用框架的开发者如果不弄清楚可能会造成内存泄露问题. 这些内存泄露问题并不是IO ...

  2. java: web应用中不经意的内存泄露

    前面有一篇讲解如何在spring mvc web应用中一启动就执行某些逻辑,今天无意发现如果使用不当,很容易引起内存泄露,测试代码如下: 1.定义一个类App package com.cnblogs. ...

  3. 查看w3wp进程占用的内存及.NET内存泄露,死锁分析

    一 基础知识 在分析之前,先上一张图: 从上面可以看到,这个w3wp进程占用了376M内存,启动了54个线程. 在使用windbg查看之前,看到的进程含有 *32 字样,意思是在64位机器上已32位方 ...

  4. 对Castle Windsor的Resolve方法的解析时new对象的探讨

    依赖注入框架Castle Windsor从容器里解析一个实例时(也就是调用Resolve方法),是通过调用待解析对象的构造函数new一个对象并返回,那么问题是:它是调用哪个构造函数呢? 无参的构造函数 ...

  5. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  6. 基于HTML5的WebGL应用内存泄露分析

    上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...

  7. android:布局、绘制、内存泄露、响应速度、listview和bitmap、线程优化以及一些优化的建议!

    1.布局优化 首先删除布局中无用的控件和层级,其次有选择地使用性能较低的viewgroup,比如布局中既可以使用RelativeLayout和LinearLayout,那我们就采用LinearLayo ...

  8. js内存泄露的几种情况详细探讨

    内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束.在C++中,因为是手动管理内存,内存泄露是经常出现的事情.而现在流行的C#和Java等语言采用了自动垃圾回收方法管理内存,正常使 ...

  9. 使用Xcode7的Instruments检测解决iOS内存泄露

    文/笨笨的糯糯(简书作者)原文链接:http://www.jianshu.com/p/0837331875f0著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 作为一名iOS开发攻城狮, ...

随机推荐

  1. POCO库——Foundation组件之核心Core

    核心Core: Version.h:版本控制信息,宏POCO_VERSION,值格式采用0xAABBCCDD,分别代表主版本.次版本.补丁版本.预发布版本: Poco.h:简单地包含了头文件Found ...

  2. java的remote shell

    http://www.ganymed.ethz.ch/ssh2/ 此程序的目的是执行远程机器上的Shell脚本. [环境参数] 远程机器IP:172.17.24.212 用户名:root 密码:zhe ...

  3. JAVA中MAP值保持顺序不变

    今天在进行JAVA开发过程中,因需要使用MAP来存放数据,同时希望MAP中KEY的顺序与放入顺序保持一致. 在使用HashMap之后,发现KEY的顺序是乱序的,每次打印还不太一样.上网查询资料之后发现 ...

  4. 自定义RatingBar的一个问题(只显示显示一个星星)

    问题一: 在自定义RatingBar时在设置了numStars属性后只显示一张图(一个星星) 解答: 注意准备的替换图片千万不要使用.9PNG格式的图片,要不之后显示一张图(一个星星)! 问题二: 设 ...

  5. webrtc中APM(AudioProcessing module)的使用2

    这个其实就是从Audio_processing.h中拿出来的. APM should be placed in the signal chain as close to the audio hardw ...

  6. 一个windows下的ddos样本

    一个windows下的ddos样本. 加载器 程序运行之后会在临时目录释放出一个256_res.tmp的文件 之后将该文件移动至system32目录下,以rasmedia.dll命名. 删除原文件. ...

  7. ASP.NET 一句代码实现批量数据绑定

    摘要:对于一个以数据处理为主的应用中的UI层,我们往往需要编写相当多的代码去实现数据绑定.如果界面上的控件和作为数据源的实体类型之间存储某种约定的映射关系,我们就可以实现批量的数据绑定,作者开发了的插 ...

  8. Unreal4教程总结

    一些好的教程分享 Ue4大神的博客 http://www.tomlooman.com 关于CustomDepth的文章的翻译 http://gad.qq.com/program/translatevi ...

  9. ORACLE如何比较两个数据库的差异

    ORACLE怎么比较两个数据库的差异 方法1:使用PL-SQL工具 点击 工具->比较用户对象

  10. 1_MVC+EF+Autofac(dbfirst)轻型项目框架_core层(以登陆为例)

    前言 在上一篇0_MVC+EF+Autofac(dbfirst)轻型项目框架_基本框架中,我已经介绍了这个轻型框架的层次结构,在下面的这篇文章中,我将以教师登陆功能为例,具体来扩充下我的core层的代 ...