Memory Leak - ProjectionRowProjectorFunc

Posts   
 
    
siegemos
User
Posts: 47
Joined: 25-Jun-2007
# Posted on: 08-Mar-2018 13:29:32   

I'm encountering a memory leak in my application.

I'm building quite a complex Linq to LLBLGen expression tree in order to create an object that stores lots of data from the db.

The issue is that this large object is then sticking around in memory long after I need it and I can't work out how to kill it as it seems to be LLBLgen code that's holding on to it.

I've profiled the app and I end up with this retention graph:

GC Handle System.Object[] System.Collections.Generic.Dictionary<string, Delegate> System.Collections.Generic.Dictionary<TKey, TValue>+Entry<string, Delegate>[] SD.LLBLGen.Pro.ORMSupportClasses.ProjectionRowProjectorFunc System.Runtime.CompilerServices.Closure System.Object[] EntitlementContext <-- This is my large object populated from a Linq to LLBLGen expression.

Any pointers on where I might be going wrong here?

We're using LLBLGen Pro 5.0.6

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 08-Mar-2018 14:46:25   

Entities which are cached, are kept in memory by the entities referencing them.

Consider Customer - Order. If you fetch both, the Customer references its orders through its Orders navigator, the collection it contains, and all orders inside that collection reference the customer.

So if you then cache the Customer, you also cache the orders. Now this is obvious. What's not obvious is when you e.g. fetch an order, myOrder, and you associate it with this cachedCustomer: myOrder.Customer = cachedCustomer;

this now also adds 'myOrder' to cachedCustomer.Orders, and thus is kept in memory too.

In general if you want to cache entities, make sure they don't have navigators, or at least not the navigators on the PK side (so in my example, the Customer.Orders navigator should be deleted in the designer). This way, doing myOrder.Customer=cachedCustomer; won't add myOrder to the Orders collection as it's not there simple_smile

So in my example, if you cache myOrder, you also cache the associated customer, and its entities. It's a graph, so things point to one another.

You have to make sure the data you cache doesn't have references to entities it shouldn't be having. The large object you're fetching, is that used somewhere where you create associations with it?

Frans Bouma | Lead developer LLBLGen Pro
siegemos
User
Posts: 47
Joined: 25-Jun-2007
# Posted on: 08-Mar-2018 15:53:32   

Thanks Frans, I understand that. My issue though is that I'm not caching anything, I'm literally populating a local variable with an object built straight from a Linq To LLBLGen query and the object is kept in memory even ouside the scope of the method, and web request.

It appears to me from looking at the graph that SD.LLBLGen.Pro.ORMSupportClasses.ProjectionRowProjectorFunc or one of it's ancesters is holding on to it.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39614
Joined: 17-Aug-2003
# Posted on: 08-Mar-2018 16:19:01   

siegemos wrote:

Thanks Frans, I understand that. My issue though is that I'm not caching anything, I'm literally populating a local variable with an object built straight from a Linq To LLBLGen query and the object is kept in memory even ouside the scope of the method, and web request.

hmm.

It appears to me from looking at the graph that SD.LLBLGen.Pro.ORMSupportClasses.ProjectionRowProjectorFunc or one of it's ancesters is holding on to it.

I don't really know how, as the only thing cached there is the projector func lambda, but that's not referencing anything. What graph exactly are you looking at? In a memory profiler? Can you exactly trace back where what is allocated then and how that graph looks like so we know what you're referring to... simple_smile

Frans Bouma | Lead developer LLBLGen Pro
siegemos
User
Posts: 47
Joined: 25-Jun-2007
# Posted on: 08-Mar-2018 17:12:43   

the only thing cached there is the projector func lambda, but that's not referencing anything

OK, this actually helped me fix the problem! Here's what I was doing:

I had an object of type EntitlementContext, this had a dictionary of child objects of type UserEntitlementContext. The dictionary was being built from a Linq to LLBLGen query inside a method "GetUserEntitlementContexts".

private IDictionary<Guid, UserEntitlementContext> GetUserEntitlementContexts(IEntitlementContext parentContext)
{
    var userContextData = 
    from u in User ...
    ...
    select new UserEntitlementContext{
          ...
          ...
        Context = parentContext
    }

    return userContextData.ToDictionary(...);
}

Now, because I was setting a property "Context" within the query and there was a cyclical reference between EntitlemtentContext and UserEntitlementContext (bad design), this seems to have caused the context object and all of it's children to get cached with the project func lambda. That's my understanding anyway and taking the Context property out of the query fixes the problem.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 08-Mar-2018 18:25:16   

This must be it, glad you found it.

Thanks for the feedback.