【问题标题】:Does this implementation of the Entity Framework leaks memory?实体框架的这种实现是否会泄漏内存?
【发布时间】:2011-07-28 19:20:08
【问题描述】:

当在 Web 应用程序或控制台应用程序的 using 语句中使用实体上下文时,我无法确定实体上下文是否在使用流程中进行了处理。

谢谢!

using System;
using System.Web;

namespace Foo.Model
{
    public partial class FooEntities : ObjectContext
    {
        private const string CurrentContextKey = "FooEntities.Current";

        [ThreadStatic]
        private static FooEntities _currentOnThreadStatic;
        private FooEntities _previousContext;

        /// <summary>
        /// Gets the current <see cref="FooEntities"/> instance, if an instance can be shared in the current context.
        /// </summary>
        /// <remarks>
        /// The current context is stored in the HTTP context, if it is available (otherwise it is stored in a thread-static instance).
        /// Multiple contexts can be stacked.
        /// </remarks>
        public static FooEntities Current
        {
            get
            {
                if (HttpContext.Current != null)
                {
                    return HttpContext.Current.Items[CurrentContextKey] as FooEntities;
                }
                else
                {
                    return _currentOnThreadStatic;
                }
            }

            private set
            {
                if (HttpContext.Current != null)
                {
                    HttpContext.Current.Items[CurrentContextKey] = value;
                }
                else
                {
                    _currentOnThreadStatic = value;
                }
            }
        }

        /// <summary>
        /// Returns a repository instance bound to this object context.
        /// </summary>
        /// <typeparam name="TRepository">The type of repository to instantiate.</typeparam>
        /// <returns>The repository instance.</returns>
        public TRepository GetRepository<TRepository>()
            where TRepository: BaseRepository
        {
            return (TRepository) Activator.CreateInstance(typeof(TRepository), this);
        }

        /// <summary>
        /// Ensures that an ambient context is available through <see cref="Current"/>, throwing an exception otherwise.
        /// </summary>
        /// <exception type="InvalidOperationException)">
        /// Thrown if <see cref="Current"/> is null.
        /// </exception>
        public static void EnsureContext()
        {
            if (Current == null)
            {
                throw new InvalidOperationException("An ambient FooEntities context is expected.");
            }
        }

        /// <summary>
        /// Releases the context instance.
        /// </summary>
        /// <param name="disposing"></param>
        protected override void Dispose(bool disposing)
        {
            Current = _previousContext;
            base.Dispose(disposing);
        }

        /// <summary>
        /// Is called by all constructors.
        /// </summary>
        partial void OnContextCreated()
        {
            _previousContext = Current;
            Current = this;
        }
    }
}

【问题讨论】:

  • 您是否有理由尝试将 ObjectContext 存储在您的 HttpContext 中?上下文被认为是轻量级的,通常您在需要时创建一个实例,然后将其丢弃。
  • 因此 FooEntities.Current 可以用于不同的类,因此您不必在构造函数中注入实例并在所有这些类中保持相同的实例。
  • 我认为您应该阅读这篇文章:stackoverflow.com/questions/3653009/… 这有望促使您重新考虑该线程静态上下文。
  • @Ladislav Mrnka:我认为实现 id c*&p。我不支持它,我也没有写它,也没有想象它。我相信实体上下文应该被注入到需要访问模型的类中,并且顶级请求处理程序应该实例化它。丑丑丑丑!归根结底,我同意你的看法,希望没有人把它作为一个例子来说明该做什么,而是做什么。

标签: c# entity-framework-4 memory-leaks idisposable disposable


【解决方案1】:

这是一个奇怪的设计。正如@Joel C 在他的评论中指出的那样,您应该将对象上下文视为您在需要时创建并在之后立即释放的短暂对象。

但我看不出这会泄漏内存的原因。您只处理托管资源,并且始终使用相同的密钥来访问 HttpContext,因此您不会创建新对象。

【讨论】:

  • ObjectContext 是 IDisposable,因此它不是托管资源。这就是我担心内存泄漏的原因。
  • @Four:抱歉,之前没有看到OnContextCreated,但我仍然认为这很好,因为保持链表活动的“锚”是HttpContext,它本身的寿命很短。
  • 它更像是一个内存“气球”,而不是内存泄漏。一切最终都会被释放,所以从技术上讲,这不是泄漏。但是在最终处理之前加载到上下文中的实体越多,用于更改跟踪、跟踪关系等的内存就越多。
  • @Anders 不是真的,终结器确保释放 托管 资源。如果您使用 unmanaged 资源(例如句柄),则您需要自己负责,并且不正确地处理您的对象会导致内存泄漏。但它最常用于托管资源,以确保及时处理事物,而不是等待 GC,例如数据库连接。
  • @Joel:如果遵循实现IDiposable 的普通模式,终结器将调用Dispose(false),它应该释放所有非托管资源。 false 标志告诉Dispose(bool disposing) 它应该忽略任何托管引用,只释放非托管资源。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 2020-11-01
  • 2016-08-16
  • 2011-05-16
  • 2016-06-16
  • 1970-01-01
相关资源
最近更新 更多