Recently I’ve found out that we can easily cause a memory leaks in our .net application by improper usage of the dependency injection container Autofac.

The case of this problem concerns only components that implements IDisposable interface, so are meant to handle some unmanaged resources and need to be disposed when no longer needed. Let me show you how to reproduce this problem in an example. For the sake of presentation both, the component and testing code are as simple as possible and do nothing really usable. 
The disposable component is defined as follows

 public class MyComponent : IDisposable
{
public MyComponent()
{
//component created
} ~MyComponent()
{
//component garbage collected
} public void Dispose()
{
//component disposed
}
}

So we got a constructor, finalizer and the Dispose() method. The most important for us is when the finalizer is called, which means that the instance of MyComponent is being released and collected by a garbage collector. 
Now let’s do write some testing code with use of Autofac container

 static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyComponent>();
var container = builder.Build();
test(container);
GC.Collect();
GC.WaitForPendingFinalizers();
} public static void test(ILifetimeScope scope)
{
using (var auxComponent = scope.Resolve<MyComponent>())
{ }
}

First we register MyComponent and build the container. Then, in test method, we ask the container to resolve the component for us in a using block. As we know the disposable object auxComponent, created in scope ofusing block is automatically disposed when runtime leaves the using block. And that is true as we can easily check by placing a breakpoint in Dispose() method of the component and running above code. 
However, the using block is also a scope for the instance of MyComponent which we create in it, since auxComponent variable is not reachable outside that block. Therefore we expect that the instance, we created, will be garbage collected (the component’s finalizer will be called), when we call lines 7 and 8. Unfortunately this is not happening.

The Autofac is designed in the way that by default it holds a references to all disposable components we request, and call Dispose() on them when the whole container is disposed! Yeap, somehow to avoid the situation we forgot to call dispose on those. Unfortunately that also means that those components are not collected by a GC as long as the container itself is collected!

This and other aspects of Autofac are excellently described by Nicholas Blumhardt in his blog post An Autofac Lifetime Primer.

Her I will only show you a proper and recommended way of working with IDisposable components and Autofac. 
The general advice using Autofac is to never resolve components from the root container. Always resolve and then dispose the lifetime scopes (ILifetimeScope). This prevents a memory leaks and facilitates creating units of work in the application. IDIsposable component resolved within a lifetime scope is associated to it and stays alive as long as the containing lifetime scope stays alive. 
Back to our example, let’s modify the code so that we will use a nested lifetime scope.

 static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyComponent>();
var container = builder.Build();
test(container);
GC.Collect();
GC.WaitForPendingFinalizers();
} public static void test(ILifetimeScope scope)
{
var localScope = scope.BeginLifetimeScope();
using (var auxComponent = localScope.Resolve<MyComponent>())
{ }
}

Now you can see that the finalizer of the MyComponent class is called when debugger reaches lines 7 and 8. The component is resolved from nested lifetime scope and is successfully collected since the localScope exists only within a test method. 
Here the component is disposed because we keep it within a using block. If we want the Autofac to handle the disposal of the resolved components for us we need to dispose the lifetime scope itself instead.

 static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<MyComponent>();
var container = builder.Build();
test(container);
GC.Collect();
GC.WaitForPendingFinalizers();
} public static void test(ILifetimeScope scope)
{
using (var localScope = scope.BeginLifetimeScope())
{
var auxComponent = localScope.Resolve<MyComponent>();
var auxComponent2 = localScope.Resolve<MyComponent>();
}
}

Now both instances of the MyComponent class are disposed and available for GC collection at the end of usingblock.

Memory leak by misusing Autofac的更多相关文章

  1. Android 内存管理 &Memory Leak & OOM 分析

    转载博客:http://blog.csdn.net/vshuang/article/details/39647167 1.Android 进程管理&内存 Android主要应用在嵌入式设备当中 ...

  2. quartz集群报错but has failed to stop it. This is very likely to create a memory leak.

    quartz集群报错but has failed to stop it. This is very likely to create a memory leak. 在一台配置1核2G内存的阿里云服务器 ...

  3. 山东省第七届ACM省赛------Memory Leak

    Memory Leak Time Limit: 2000MS Memory limit: 131072K 题目描述 Memory Leak is a well-known kind of bug in ...

  4. caching redirect views leads to memory leak (Spring 3.1)

    在Spring 3.1以及以下版本使用org.springframework.web.servlet.view.UrlBasedViewResolver + cache(如下配置),在会出现任意种re ...

  5. 一则JVM memory leak解决的过程

    起因是我们的集群应用(3台机器)新版本测试过程中,一般的JVM内存占用 都在1G左右, 但在运行了一段时间后,慢慢升到了4G, 这是一个明显不正常的现象. 定位 过程: 1.先在该机器上按照步骤尝试重 ...

  6. Linux C/C++ Memory Leak Detection Tool

    目录 . 内存使用情况分析 . 内存泄漏(memory leak) . Valgrind使用 1. 内存使用情况分析 0x1: 系统总内存的分析 可以从proc目录下的meminfo文件了解到当前系统 ...

  7. SilverLight - Memory Leak

    There is a memory leak issue in current silverlight project. It occurs in the search function: the m ...

  8. A memory leak issue with WPF Command Binding

    Background In our application, we have a screen which hosts several tabs. In each tab, it contains a ...

  9. quartzScheduler_Worker-1] but has failed to stop it. This is very likely to create a memory leak解决

    01-Jul-2016 07:24:20.218 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 80 ...

随机推荐

  1. 关于命名空间namespace

    虽然任意合法的PHP代码都可以包含在命名空间中,但只有以下类型的代码受命名空间的影响,它们是:类(包括抽象类和traits).接口.函数和常量. 在声明命名空间之前唯一合法的代码是用于定义源文件编码方 ...

  2. ogg高版本到低版本同步

    源端ogg版本: [oracle@rac1 ogg]$ ggsci -v Oracle GoldenGate Command Interpreter for Oracle Version 11.2.1 ...

  3. C++Builder中的延时函数

    第一种方法: 使用 Sleep(1000) 函数 如果使用Sleep(1000);的时候提示如此错误   [C++ Error] supplierPayment_.cpp(321): E2015 Am ...

  4. 从客户端中检测到有潜在危险的 Request.Form 值的问题的解决方法。

    在controller控制器里面添加[ValidateInput(false)]         [ValidateInput(false)]        public ActionResult m ...

  5. Java启动参数及调优

    java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容:其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且 ...

  6. slam学习

    学习内容: 数学: 线性代数,概率论, 优化理论,离散数学, 李代数, 凸优化: 算法:   概率机器人, 机器人状态估计, 深度学习,非线性优化: 工程: c/c++ , python, ros, ...

  7. 编程之美Ex1——求二进制中1的个数

    又被阿里机考虐了一次,决定改变策略开始刷题T^T 一个字节(8bit)的无符号整型,求其二进制中的“1”的个数,算法执行效率尽可能高. 最先想到的移位操作,末尾位&00000001,然后右移, ...

  8. HihoCoder1050 树中的最长路 树形DP第三题(找不到对象)

    题意:求出的树中距离最远的两个结点之间相隔的距离. 水题一道,以前只会用路的直径来解. 代码如下: #include<cstdio> #include<cstdlib> #in ...

  9. EM算法定义及推导

    EM算法是一种迭代算法,传说中的上帝算法,俗人可望不可及.用以含有隐变量的概率模型参数的极大似然估计,或极大后验概率估计 EM算法定义 输入:观测变量数据X,隐变量数据Z,联合分布\(P(X,Z|\t ...

  10. 关于swagger文档的使用方法

    引言 最近在后台开发的时候,使用swagger2进行前后台接口文档的声明.由此遇见的一些问题,写下来给自己复习. 参考: https://blog.csdn.net/xupeng874395012/a ...