locked
DLinq and memory leaking. RRS feed

  • Question

  • Hi!
    See this code:

    customer = new Customer();
    customer.Name = "Danilo";
    WeakReference wk = new WeakReference(customer);
    customer = null;
    GC.Collect();

    Running this code, after the Collect, the customer instance is correctly collected by GC. customer is a global static field. But, take a look at this:

    DbCustomerDataContext context = new DbCustomerDataContext();
    customer = new Customer();
    customer.Name = "Danilo";
    context.Customers.Add(customer);
    context.SubmitChanges();
    WeakReference wk = new WeakReference(customer);
    customer = null;
    context.Dispose();
    context = null;
    GC.Collect();

    This time, customer isn't collected by GC. It's clear that my code isn't holding anymore instances. So I think, the Dlinq engine somewhere is holding an instance. I know that GC.Collect() doesn't guarantee that all unreachable objects will be reclaimed but I think it's unlikely that this specific behavior is happening, since in the first code, customer is always collected.

    My question is: Is there any known memory leak issue with dlinq? Am i missing something?
    Will customer stay in memory forever? That's really the question...
    Thanks in advance.
    Sunday, September 23, 2007 5:55 PM

Answers

  • We've reproduced this problem and are actively working on resolving it.  Thanks for pointing it out.

     

    Tuesday, September 25, 2007 5:48 PM
  • We have taken the bug fix for this issue for RTM. Since the product is almost locked down, we had to take it through a bunch of hoops (approvals) but that is done.

     

    Thanks again for pointing this out.
    Dinesh

     

    Friday, September 28, 2007 4:40 PM

All replies

  • Well, after profiling my app with ANTS Profiler, I discovered that even the data context isn't reclaimed by GC. Classes on the DLinq engine; like CommonDataServices, ChangeTracker and so on; are still holding references to the data context (even after it being disposed) and instances of the entity class Customer. Why this happen? Will customer and the data context be reclaimed by GC or they'll stay in memory during the whole lifetime of my app?

     

    If the data context and entity classes are never released, it'll be impossible for, let's say, load the entire database (load and release small parts of the database until the entire set of rows is processed).

    Someone help, please!!!

    Monday, September 24, 2007 4:19 PM
  • When you call Dispose on the DataContext, the data context forces the connection to close (if it is not already closed, which it normally is) and dumps its cache. This means the DataContext is no longer referencing any of the objects that you previously retrieved. However, these objects may be still referencing the DataContext via unresolved/unloaded EntitySet's and EntityRef's. That's okay though, since unless you are holding onto the entity object everything should get cleaned up by garbage collection.  The DataContext is references by some of its internal parts, but those should get cleaned up regardless.  There are no global or static references to any of these. 

     

    There are global references to the mapping source though. There is a static field of the DataContext that is generated by designer/SQLMetal that holds onto the mapping source so that it can be reused.  The mapping source does not hold onto any DataContext instances though.

     

    There differences you are seeing may be due to different generations of garbarge collection.  I'm not expert on the GC.

    Monday, September 24, 2007 6:58 PM
  • I think I found why the data context and the Customer entity instance wasn't being collected by the GC. Taking a snapshot, in ANTS Profiler, after the GC.Collect(), i found that the customer instance is referenced from a System.Linq.Expressions.ConstantExpression instance. The ConstantExpression instance is referenced from a SqlColumnRef instance. The SqlColumnRef is referenced from a SqlClientArray instance (it's inside a List<T> on the SqlClientArray instance). The SqlClientArray instance is referenced from a ObjectReaderCompiler.ReaderFactoryCache.CacheInfo instance. The CacheInfo instance is referenced from a ObjectReaderCompiler.ReaderFactoryCache (it's inside a LinkedList<T> on the ReaderFactoryCache instance). The ReaderFactoryCache instance is inside a object[] array. And this object[] array is inside a LocalDataStore instance. This LocalDataStore instance is inside an ArrayList instance which is inside a LocalDataStoreMgr instance. The LocalDataStoreMgr instance is inside a LocalDataStoreSlot instance. This LocalDataStoreSlot instance is only referenced from a static object[] array wich ANTS profiler says that is allocated by the CLR initialization.

     

    In other words, the Customer instance cannot be released from memory because the dlinq engine stored it indirectly in a LocalDataStoreSlot on the thread. Since the Customer instance points to the data context, it isn't released too.

    Can you tell me, if the customer instance will stay there forever?

    Monday, September 24, 2007 10:10 PM
  • We've reproduced this problem and are actively working on resolving it.  Thanks for pointing it out.

     

    Tuesday, September 25, 2007 5:48 PM
  • Could you give us the exact build number? If you use

    db.Log = Console.Out;

    The output will show an exact DLL build number. Could you please post/send that?

     

    Thanks,
    Dinesh

    Tuesday, September 25, 2007 6:27 PM
  • The builder number is 3.5.20706.1. That's exactly what appears. Thanks in advance and I'm looking forward to the rtm version of Visual Studio 2008 and i'll assume that this issue will be resolved.

    Tuesday, September 25, 2007 9:15 PM
  • We have taken the bug fix for this issue for RTM. Since the product is almost locked down, we had to take it through a bunch of hoops (approvals) but that is done.

     

    Thanks again for pointing this out.
    Dinesh

     

    Friday, September 28, 2007 4:40 PM
  • Thread blast from the past --- last replied in 2007.

    Did this problem make it back into the 4.0 run-time?  We are using this and have the exact same problem with 4.0 at the moment.  Thousands of instances of SqlNew and SqlMemberAssign. When looking them up in the memory profile, they are all rooted in the ReaderFactoryCache/LocalDataStore for the thread.  Even though we dispose of the DataContext when we are done (using(){}), it just continues to climb in instance count.   We are polling a 2 views in a database once a second, with a query that changes slightly by a DateTime.   I am hoping we are doing something wrong, but it seems like this exact problem reported above is happening to a service app we have.    Here is a pic of the memory reference map.


    Travis Whidden

    Wednesday, June 12, 2013 1:21 AM