memory leak(?) problem with Validation Rules

memory leak(?) problem with Validation Rules

Old forum URL: forums.lhotka.net/forums/t/8950.aspx


rolandschwarz posted on Tuesday, May 18, 2010

 

Hello,

I am relativly new to the CSLA Business Objects Framework, I found it used in one application I am currently maintaining and cleaning up on memory usage and some leaks.

The application is a bit complex in its layout, has about 30+ tsd lines code and it is not always clear what some classes purpose is, but I'm digging into it with the time.

For the moment I'm trying to locate some nerv-biting memory leaks in the application. I have done some monitoring with the performance monitor, watching the heap values and used memprofiler.

Roughly said, the gen 2 and the large object heap keep getting bigger and get filled up with some data. Using memprofiler, I got some interesting results: It informed me of a lot of "indirect delegate roots" and "indirect event handler roots". On further investigation I found, that there are references left to CSLA.ValidationRules, that remain in memory and keep the GC from cleaning up those object.

So what I know of the CSLA Framework, the Validation Rules purpose is to i.e. provide a active check if a data object ( textual input ) follows given rules ( non-empty, credit card number format, valid US-phone number  etc. ) .

I see Validation rules added to data objects, like for example those :

            ValidationRules.AddInstanceRule(CommonRules.StringNotEmpty, new RuleArgs("Name", Resources.PropertyFriendlyNameForName));
            ValidationRules.AddInstanceRule(CommonRules.StringDoesNotExceedLength, new CommonRules.StringLengthRuleArgs("Name", Resources.PropertyFriendlyNameForName, 255));
            ValidationRules.AddInstanceRule(CommonRules.NotOnlyDigits, new RuleArgs("Name", Resources.PropertyFriendlyNameForName));

 

In my profiling results with mem profiler, I see then the reference back to those rules, results look like that:

( copyNpaste from memprofiler, not completly expanded as there seem to be circular references )

PointOfInterestType    #1.230.761._validationRules
    InternationalizedString.TranslationsChangedDelegate    #1.216.822._target
    ValidationRules    #1.256.839._target
        PointOfInterestType    #1.230.761._validationRules
            InternationalizedString.TranslationsChangedDelegate    #1.216.822._target
                Object[]    #1.202.793[5501]
                    InternationalizedString.TranslationsChangedDelegate    #1.200.429._invocationList
                        InternationalizedString    #196.057.TranslationsChanged
                        InternationalizedString.TranslationsChangedDelegate    #1.200.429._target
            ValidationRules    #1.256.839._target
                PointOfInterestType    #1.230.761._validationRules
                    InternationalizedString.TranslationsChangedDelegate    #1.216.822._target
                        Object[]    #1.202.793[5501]
                            InternationalizedString.TranslationsChangedDelegate    #1.200.429._invocationList
                                InternationalizedString    #196.057.TranslationsChanged
                                InternationalizedString.TranslationsChangedDelegate    #1.200.429._target
                    ValidationRules    #1.256.839._target

So, I ask myself where to look further to solve this problem and came to the idea maybe to ask here, and in paralell start reading bits in the Business objects book ;-) .

Do these validation rules somehow get cleaned up if the object is to be disposed ? In the whole application, there is no Dispose or Finalize implemented, even some manually added event handlers do not get removed, so maybe that is the point that causes the cleanup problem, as there are still references left.

So why I post here and ask is to find a discussion basis and some more information where to investigate further.

The application uses the CSLA Version 3.0.3.0 from about 2007, the application is written for .NET 3.5 in C#.

Thanks alot for some ideas !

 

Greetings !

roland

RockfordLhotka replied on Tuesday, May 18, 2010

Validation rules are loaded once per-AppDomain per business object type. They are kept in a static cache and so are shared across all instances of the business object type. Because they are loaded in a static cache they are never unloaded - that is intentional, because reloading them frequently would be (and was in version 2.0) a major performance issue.

But this wouldn't normally be considered a "memory leak" because the cache doesn't just keep growing either. It'll expand as the app first runs, but once you've touched every business object type it is done - all the rules will have been loaded and that's that.

rolandschwarz replied on Tuesday, May 18, 2010

Hello,

Maybe I used a formulation that was a bit imprecise ;-) .( maybe there were some caffeine molecules missing in my brain )

I'm not considering the Validation Rules and their implementation as a memory leak, in fact the way they are implemented it seems to be a good way between performance and memory usage. How I came to investige into the ValidationRules was as they turned up in that listing from memProfiler, and it seemed to me that there were references left to/from the created validation rules that prevented the GC from colleting away some object.

The problem with this whole issue is the following:

The app. does some displaying of data, and each display instance consumes up from at leat 10 to 60 mb memory in the privates bytes, and adds also up the values on the heaps, mainly on the gen2 heap and the larg object heap. They grow about 4-8 megs on the gen2 heap and about 2 megs on the large object heap every time the user goes from one document to the next.

Normally the current document data should get cleaned out, there is also one routine, that asks for "termination", but the process has no relevant impact on the heap values.

So I am investigating and stumbled on to references left over from Validation rules, there are also a lot of event references left over that get added, at the moment I'm coding in some cleanup methods, but for now its mostly, how you say directly translated from german - "a drip of water on a hot stone" ;-) .

Maybe that clears up a little my intention on this ;-) .

 

Thanks for your help !

greetings !

 

roland

RockfordLhotka replied on Tuesday, May 18, 2010

I see, thank you for clarifying.

Normally rule methods should not maintain references to the business object. Rule methods are atomic and stateless, unless you somehow work to make them maintain state. But normally they are just a method, not an object, and so it is not possible for them to have instance-level fields that would maintain any persistent reference. Nor do they define or raise events, which would be the other way to get such a reference.

In version 2.x and 3.x the business object reference is passed into a rule as a parameter (the target parameter), and so that reference is not maintained by CSLA or by any normal rule - it is transitory.

I can't say there's not a bug or something - but the validation rules really shouldn't be the problem.

The most likely cause of memory leaks comes from events - those hidden references that come with events are often a problem.

Eirini replied on Friday, June 08, 2012

Hi,

I also noticed this memory leak by using the validate of ruleset.

Do you know how we can limit the consumed memory?

RockfordLhotka replied on Friday, June 08, 2012

So you have clear confirmation that business rules are keeping your business objects in memory when they should be disposed?

And you are absolutely certain that your business rules have no instance fields and establish no event handlers?

It is possible for an incorrectly written rule to create a memory leak. But that would be a bug in the rule, not in the framework.

Eirini replied on Friday, June 08, 2012

Thanks for your fast reply.

My rules do not establish event handlers.

Regarding instance fields, I send you one of the rules I have (All rules have almost the same format)

Condition:

!this.Request.Configuration.UPSEnabled || this.Request.DeviceStatusDetails.UpsStatusDetails.Status == Printec.SSK.Client.Administration.Utilities.PeripheralStatus.Operational

Then actions:

this.Response = True

Else actions:

this.Response = False
this.ErrorContainer.AddError("UPS is not operational!")
Halt

Are you seing something suspicious at this code?

Thanks

 

 

RockfordLhotka replied on Friday, June 08, 2012

You say you are using rulesets, so you are using CSLA 4 right?

In that case a rule is a class, and looks like this:

  public class MyRule : Csla.Rules.BusinessRule
  {
    protected override void Execute(Csla.Rules.RuleContext context)
    {
      context.AddErrorResult("Bad value");
    }
  }

Copyright (c) Marimer LLC