实体框架使用了大量的内存实体、框架、内存、使用了

2023-09-04 00:40:43 作者:叼煙不点火

下面是从蚂蚁内存分析器一个图像。其作用似乎有很多的对象在内存中举行。我怎样才能找到我做错了吗?

  **更新**
 

下面是我的仓库类:

 公共类资源库< T> :IRepository< T>其中T:类,IDataEntity
    {
        ObjectContext的_context;
        IObjectSet< T> _objectSet;

        只读字符串_entitySetName;
        只读的String [] _​​keyNames;

        私人ObjectContext的上下文
        {
            得到
            {
                如果(_context == NULL)
                {
                    _context = GetCurrentUnitOfWork< EFUnitOfWork>()语境;
                }
                返回_context;
            }
        }

        私人IObjectSet< T>对象集
        {
            得到
            {
                如果(_objectSet == NULL)
                {
                    _objectSet = this.Context.CreateObjectSet< T>();
                }
                返回_objectSet;
            }
        }

        公共TUnitOfWork GetCurrentUnitOfWork< TUnitOfWork>()其中TUnitOfWork:IUnitOfWork
        {
            返回(TUnitOfWork)UnitOfWork.Current;
        }

        公共虚拟的IEnumerable< T> GetQuery()
        {
            返回对象集;
        }

        公共虚拟的IEnumerable< T> GetQuery(PARAMS防爆pression< Func键< T,对象>> []包括)
        {
            返回ObjectSet.IncludeMultiple(包括);
        }

        公共虚拟的IEnumerable< T> GetQuery(
            IEnumerable的<防爆pression< Func键< T,布尔>>>过滤器,
            FUNC< IQueryable的< T&GT ;, IOrderedQueryable< T>>排序依据,
            IEnumerable的<防爆pression< Func键< T,对象>>>包括)
        {
            IQueryable的< T> _query =对象集;

            如果(过滤器!= NULL)
            {
                的foreach(在过滤器变种过滤器)
                {
                    _query = _query.Where(过滤器);
                }
            }

            如果(包括=空&安培;!&安培; includes.Count()大于0)
            {
                _query = _query.IncludeMultiple(includes.ToArray());
            }

            如果(排序依据!= NULL)
            {
                _query =排序依据(_query);
            }

            返回_query;
        }

        公共虚拟IPaged< T> GetQuery(
            IEnumerable的<防爆pression< Func键< T,布尔>>>过滤器,
            FUNC< IQueryable的< T&GT ;, IOrderedQueryable< T>>排序依据,
            INT页面编号,诠释的pageSize,
            IEnumerable的<防爆pression< Func键< T,对象>>>包括)
        {
            IQueryable的< T> _query =对象集;

            如果(过滤器!= NULL)
            {
                的foreach(在过滤器变种过滤器)
                {
                    _query = _query.Where(过滤器);
                }
            }

            如果(排序依据!= NULL)
            {
                _query =排序依据(_query);
            }

            IPaged< T>页=新分页< T>(_查询,页面编号,pageSize的,包括);

            返回页面;
        }

        公共虚拟无效插入(T实体)
        {
            this.ObjectSet.AddObject(实体);
        }

        公共虚拟无效删除(T实体)
        {
            如果(实体ISoftDeletable)
            {
                ((ISoftDeletable)实体).IsDeleted = TRUE;
                //更新(实体);
            }
            其他
            {
                this.ObjectSet.DeleteObject(实体);
            }
        }

        公共虚拟无效连接(T实体)
        {
            ObjectStateEntry进入= NULL;
            如果(this.Context.ObjectStateManager.TryGetObjectStateEntry(实体,出项)==假)
            {
                this.ObjectSet.Attach(实体);
            }
        }

        公共虚拟空间分离(T实体)
        {
            ObjectStateEntry进入= NULL;
            如果(this.Context.ObjectStateManager.TryGetObjectStateEntry(实体,出项)==真)
            {
                this.ObjectSet.Detach(实体);
            }
        }
    }
 
索尼PlayStation 4拆解 拆装容易 维修难度低 全文

现在,如果我有A类,保存记录从表A中,我也创建类:

 公共类ARepository:BaseRepository< A> {
// A的查询执行和具体分贝操作
}
 

下面是我的EFUnitOfWork类:

 公共类EFUnitOfWork:IUnitOfWork,IDisposable的
{
    公共ObjectContext的语境{获得;私定; }

    公共EFUnitOfWork(ObjectContext的情况下)
    {
        上下文=语境;
        context.ContextOptions.LazyLoadingEnabled = TRUE;
    }

    公共无效提交()
    {
        Context.SaveChanges();
    }

    公共无效的Dispose()
    {
        如果(背景!= NULL)
        {
            Context.Dispose();
        }
        GC.Sup pressFinalize(本);
    }
}
 

和的UnitOfWork类:

 公共静态类的UnitOfWork
{
    私人常量字符串HTTPCONTEXTKEY =MyProj.Domain.Business.Repository.HttpContext.Key;

    私有静态IUnitOfWorkFactory _unitOfWorkFactory;
    私人静态只读Hashtable的_threads =新的Hashtable();

    公共静态无效提交()
    {
        IUnitOfWork的UnitOfWork = GetUnitOfWork();
        如果(的UnitOfWork!= NULL)
        {
            unitOfWork.Commit();
        }
    }

    公共静态IUnitOfWork电流
    {
        得到
        {
            IUnitOfWork的UnitOfWork = GetUnitOfWork();
            如果(的UnitOfWork == NULL)
            {
                _unitOfWorkFactory = ObjectFactory.GetInstance&其中; IUnitOfWorkFactory>();
                的UnitOfWork = _unitOfWorkFactory.Create();
                SaveUnitOfWork(的UnitOfWork);
            }
            返回的UnitOfWork;
        }
    }

    私有静态IUnitOfWork GetUnitOfWork()
    {
        如果(HttpContext.Current!= NULL)
        {
            如果(HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
            {
                返回(IUnitOfWork)HttpContext.Current.Items [HTTPCONTEXTKEY]
            }
            返回null;
        }
        其他
        {
            线程线程= Thread.CurrentThread;
            如果(string.IsNullOrEmpty(thread.Name))
            {
                。thread.Name = Guid.NewGuid()的ToString();
                返回null;
            }
            其他
            {
                锁定(_threads.SyncRoot)
                {
                    返回(IUnitOfWork)_threads [Thread.CurrentThread.Name]
                }
            }
        }
    }

    私有静态无效SaveUnitOfWork(IUnitOfWork的UnitOfWork)
    {
        如果(HttpContext.Current!= NULL)
        {
            HttpContext.Current.Items [HTTPCONTEXTKEY] =的UnitOfWork;
        }
        其他
        {
            锁定(_threads.SyncRoot)
            {
                _threads [Thread.CurrentThread.Name] =的UnitOfWork;
            }
        }
    }
}
 

下面是我如何使用这样的:

 公共类TaskPriceRepository:BaseRepository< TaskPrice>
    {
        公共无效集(TaskPrice实体)
        {
            。TaskPrice taskPrice = GetQuery()的SingleOrDefault(X => x.TaskId == entity.TaskId);
            如果(taskPrice!= NULL)
            {
                CommonUtils.CopyObject< TaskPrice>(实体,裁判taskPrice);
            }
            其他
            {
                this.Insert(实体);
            }
        }
    }

公共类BranchRepository:BaseRepository<店>
{
    公众的IList<店> GetBranchesList(GUID companyId,长时间?branchId,串分支名称)
    {
        返回Repository.GetQuery()。
            其中(B => companyId == b.CompanyId)。
            其中(B => b.IsDeleted ==假)。
            其中(B =>!branchId.HasValue || b.BranchId.Equals(branchId.Value))。
            其中(B => BRANCHNAME == NULL || b.BranchName.Contains(分支))。
            了ToList();
    }
}

[WebMethod的]
公共无效SetTaskPrice(TaskPriceDTO taskPrice)
{
    TaskPrice TP = taskPrice.ToEntity();
    TaskPriceRepository代表=新TaskPriceRepository();
    rep.Set(TP);
    UnitOfWork.Commit();
}

[WebMethod的]
公众的IList<店> GetBranchesList()
{
    BranchRepository代表=新BranchRepository();
    返回rep.GetBranchesList(m_User.UserCompany.CompanyId,NULL,NULL).ToList();
}
 

我希望这是足够的信息来帮助我解决这个问题。谢谢你。

更新2 还有UnitOfWorkFactory初始化的UnitOfWork:

 公共类UnitOfWorkFactory:IUnitOfWorkFactory
{
    私有静态函数功能:LT; ObjectContext的> _objectContextDelegate;
    私人静态只读对象_lockObject =新的对象();

    公共静态无效SetObjectContext(Func键< ObjectContext的> objectContextDelegate)
    {
        _objectContextDelegate = objectContextDelegate;
    }

    公共IUnitOfWork创建()
    {
        ObjectContext的背景下;
        锁定(_lockObject)
        {
             上下文= _objectContextDelegate();
        }
        返回新EFUnitOfWork(上下文);
    }
}
 

为了利用这一点,在应用程序启动时我用structuremap:

  ObjectFactory.Initialize(X =>
        {
            x.For&其中; IUnitOfWorkFactory>()使用<。&UnitOfWorkFactory GT;();
            x.For(typeof运算(IRepository<>)),使用(typeof运算(库<>));
        });
 

解决方案

我有一种预感,你不处理的范围内。 我建议处置,只要你做的与数据库进行交互的环境。

使用使用语句时,你创建的内容。

据我所看到的,您缓存,不处理你的 EFUnitOfWork 对象。这是一次性的,这是正确的,但我没有看到一次性时候被调用。好像你保持一个对上下文的所有应用程序的运行时间。照片此外,创建并保持一个上下文每个线程,这将使事情变得更糟。

我不能告诉你肯定你应该把处置使用,因为我不知道用法。 你可以把它可能是你的提交的方法,但我不知道,如果提交数据库中调用一次交互会话。

此外,您的设计可能会过于复杂。

如果我是你,我会:

找到使用当前的code处置的背景下,作为一个短期的解决方案的方式 简化设计,作为长期的解决方案

如果我有时间,我会做长期的解决方案的时候了。 但同样,我不能告诉,如果你设计的复杂性是有道理的,因为我不知道有多大你的应用程序是什么,它​​做什么的要求。

Here is a image from the ANTS memory profiler. It seens that there are a lot of objects hold in memory. How can I find what I am doing wrong?

**UPDATE**

Here is my repository classes:

public class Repository<T> : IRepository<T> where T : class, IDataEntity
    {
        ObjectContext _context;
        IObjectSet<T> _objectSet;

        readonly string _entitySetName;
        readonly string[] _keyNames;

        private ObjectContext Context
        {
            get
            {
                if (_context == null)
                {
                    _context = GetCurrentUnitOfWork<EFUnitOfWork>().Context;
                }
                return _context;
            }
        }

        private IObjectSet<T> ObjectSet
        {
            get
            {
                if (_objectSet == null)
                {
                    _objectSet = this.Context.CreateObjectSet<T>();
                }
                return _objectSet;
            }
        }

        public TUnitOfWork GetCurrentUnitOfWork<TUnitOfWork>() where TUnitOfWork : IUnitOfWork
        {
            return (TUnitOfWork)UnitOfWork.Current;
        }

        public virtual IEnumerable<T> GetQuery()
        {
            return ObjectSet;
        }

        public virtual IEnumerable<T> GetQuery(params Expression<Func<T, object>>[] includes)
        {
            return ObjectSet.IncludeMultiple(includes);
        }

        public virtual IEnumerable<T> GetQuery(
            IEnumerable<Expression<Func<T, bool>>> filters,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
            IEnumerable<Expression<Func<T, object>>> includes)
        {
            IQueryable<T> _query = ObjectSet;

            if (filters != null)
            {
                foreach (var filter in filters)
                {
                    _query = _query.Where(filter);
                }
            }

            if (includes != null && includes.Count() > 0)
            {
                _query = _query.IncludeMultiple(includes.ToArray());
            }

            if (orderBy != null)
            {
                _query = orderBy(_query);
            }

            return _query;
        }

        public virtual IPaged<T> GetQuery(
            IEnumerable<Expression<Func<T, bool>>> filters,
            Func<IQueryable<T>, IOrderedQueryable<T>> orderBy,
            int pageNumber, int pageSize,
            IEnumerable<Expression<Func<T, object>>> includes)
        {
            IQueryable<T> _query = ObjectSet;

            if (filters != null)
            {
                foreach (var filter in filters)
                {
                    _query = _query.Where(filter);
                }
            }

            if (orderBy != null)
            {
                _query = orderBy(_query);
            }

            IPaged<T> page = new Paged<T>(_query, pageNumber, pageSize, includes);

            return page;
        }

        public virtual void Insert(T entity)
        {
            this.ObjectSet.AddObject(entity);
        }

        public virtual void Delete(T entity)
        {
            if (entity is ISoftDeletable)
            {
                ((ISoftDeletable)entity).IsDeleted = true;
                //Update(entity);
            }
            else
            {
                this.ObjectSet.DeleteObject(entity);
            }
        }

        public virtual void Attach(T entity)
        {
            ObjectStateEntry entry = null;
            if (this.Context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry) == false)
            {
                this.ObjectSet.Attach(entity);
            }
        }

        public virtual void Detach(T entity)
        {
            ObjectStateEntry entry = null;
            if (this.Context.ObjectStateManager.TryGetObjectStateEntry(entity, out entry) == true)
            {
                this.ObjectSet.Detach(entity);
            }
        }
    }

Now, if I have class A that holds records from table A, I also create class:

public class ARepository:BaseRepository<A> {
// Implementation of A's queries and specific db operations
}

Here is my EFUnitOfWork class:

public class EFUnitOfWork : IUnitOfWork, IDisposable
{
    public ObjectContext Context { get; private set; }

    public EFUnitOfWork(ObjectContext context)
    {
        Context = context;
        context.ContextOptions.LazyLoadingEnabled = true;
    }

    public void Commit()
    {
        Context.SaveChanges();
    }

    public void Dispose()
    {
        if (Context != null)
        {
            Context.Dispose();
        }
        GC.SuppressFinalize(this);
    }
}

And UnitOfWork class:

public static class UnitOfWork
{
    private const string HTTPCONTEXTKEY = "MyProj.Domain.Business.Repository.HttpContext.Key";

    private static IUnitOfWorkFactory _unitOfWorkFactory;
    private static readonly Hashtable _threads = new Hashtable();

    public static void Commit()
    {
        IUnitOfWork unitOfWork = GetUnitOfWork();
        if (unitOfWork != null)
        {
            unitOfWork.Commit();
        }
    }

    public static IUnitOfWork Current 
    {
        get
        {
            IUnitOfWork unitOfWork = GetUnitOfWork();
            if (unitOfWork == null)
            {
                _unitOfWorkFactory = ObjectFactory.GetInstance<IUnitOfWorkFactory>();
                unitOfWork = _unitOfWorkFactory.Create();
                SaveUnitOfWork(unitOfWork);
            }
            return unitOfWork;
        }
    }

    private static IUnitOfWork GetUnitOfWork()
    {
        if (HttpContext.Current != null)
        {
            if (HttpContext.Current.Items.Contains(HTTPCONTEXTKEY))
            {
                return (IUnitOfWork)HttpContext.Current.Items[HTTPCONTEXTKEY];
            }
            return null;
        }
        else
        {
            Thread thread = Thread.CurrentThread;
            if (string.IsNullOrEmpty(thread.Name))
            {
                thread.Name = Guid.NewGuid().ToString();
                return null;
            }
            else
            {
                lock (_threads.SyncRoot)
                {
                    return (IUnitOfWork)_threads[Thread.CurrentThread.Name];
                }
            }
        }
    }

    private static void SaveUnitOfWork(IUnitOfWork unitOfWork)
    {
        if (HttpContext.Current != null)
        {
            HttpContext.Current.Items[HTTPCONTEXTKEY] = unitOfWork;
        }
        else
        {
            lock(_threads.SyncRoot)
            {
                _threads[Thread.CurrentThread.Name] = unitOfWork;
            }
        }
    }
}

Here is how I use this:

 public class TaskPriceRepository : BaseRepository<TaskPrice>
    {
        public void Set(TaskPrice entity)
        {
            TaskPrice taskPrice = GetQuery().SingleOrDefault(x => x.TaskId == entity.TaskId);
            if (taskPrice != null)
            {
                CommonUtils.CopyObject<TaskPrice>(entity, ref taskPrice);
            }
            else
            {
                this.Insert(entity);
            }
        }
    }

public class BranchRepository : BaseRepository<Branch>
{
    public IList<Branch> GetBranchesList(Guid companyId, long? branchId, string branchName)
    {
        return Repository.GetQuery().
            Where(b => companyId == b.CompanyId).
            Where(b => b.IsDeleted == false).
            Where(b => !branchId.HasValue || b.BranchId.Equals(branchId.Value)).
            Where(b => branchName == null || b.BranchName.Contains(branchName)).
            ToList();
    }
}

[WebMethod]
public void SetTaskPrice(TaskPriceDTO taskPrice)
{
    TaskPrice tp = taskPrice.ToEntity();
    TaskPriceRepository rep = new TaskPriceRepository();
    rep.Set(tp);
    UnitOfWork.Commit();
}

[WebMethod]
public IList<Branch> GetBranchesList()
{
    BranchRepository rep = new BranchRepository();
    return rep.GetBranchesList(m_User.UserCompany.CompanyId, null, null).ToList();
}

I hope this is enough info to help me solving the problem. Thanks.

UPDATE 2 There is also UnitOfWorkFactory that initializes UnitOfWork:

public class UnitOfWorkFactory : IUnitOfWorkFactory
{
    private static Func<ObjectContext> _objectContextDelegate;
    private static readonly Object _lockObject = new object();

    public static void SetObjectContext(Func<ObjectContext> objectContextDelegate)
    {
        _objectContextDelegate = objectContextDelegate;
    }

    public IUnitOfWork Create()
    {
        ObjectContext context;
        lock (_lockObject)
        {
             context = _objectContextDelegate();
        }
        return new EFUnitOfWork(context);
    }
}

In order to use this, in the application startup I use structuremap:

  ObjectFactory.Initialize(x =>
        {
            x.For<IUnitOfWorkFactory>().Use<UnitOfWorkFactory>();
            x.For(typeof(IRepository<>)).Use(typeof(Repository<>));
        });

解决方案

I have a hunch you don't dispose the context. I suggest disposing the context whenever you done interacting with database.

Use using statement whenever you create the context.

[Edit]

As far as I can see, you cache and don't dispose your EFUnitOfWork object. It is disposable, which is correct, but I don't see when disposable is called. Seems like you hold a reference to the context for all application run time. Moreover, you create and hold one context per thread, which will make it even worse.

I can't tell you for sure where you should put Dispose or using, as I don't know the usages. You could put it probably to your Commit method, but I don't know if the Commit called only once during database interaction session.

Also, your design might be overcomplicated.

If I were you, I would:

Find the way to dispose the context using current code, as a short-term solution Simplify the design, as the long-term solution

If I had time I would do long-term solution right away. But again, I can't tell if the complexity of your design is justified, as I don't know how big your application is and what it does and what the requirements are.

 
精彩推荐
图片推荐