Results 1 to 7 of 7

Thread: Poor performance of XmlApplicationContext.Dispose()

  1. #1
    Join Date
    Jun 2007
    Posts
    17

    Default Poor performance of XmlApplicationContext.Dispose()

    Of all my application objects (all 1400+ of them) that are registered/created through Spring, only a small percentage of them define cleanup code. In other words, only about 2% of my application objects either define IDisposable or a "destroy-method" method. And for those that do the cleanup code is very lightweight. Yet when Dispose() is invoked on the XmlApplicationContext it takes upwards of 60 seconds to destroy all 1400+ objects. This comes out to about 45ms per object and makes for a very slow application shutdown. Looking at the logs, there isn't any one single object responsible for the delay -- all objects take an equal amount of time to be destroyed.

    Is there something obvious I am missing -- a simple configuration change perhaps? I can't think of anything that would cause this kind of performance issue. I am currently on version 1.3.1 and running in a .NET 4.0 environment.

  2. #2
    Join Date
    Jun 2007
    Posts
    17

    Default Spring is not scalable

    The problem appears to be the scalability of Spring. The more objects you define in Spring the worse the performance gets when disposing a Spring context. In my application the main object factory in Spring has 2956 object definition names. During disposal the factory destroys dependent objects, recursively looping through the object hierarchy and disposing/destroying each applicable object. The problem is that this recursion takes an eternity and makes disposing the context impractical.

    The change I tinkered with that improved the performance of disposal is to destroy dependent objects only if the current object is itself disposable/destroyable. This resulted in a 75% improvement in performance. The only thing stopping me from getting a larger improvement are AbstractFactoryObject objects. The call to destroy dependent objects is likely wasted on these objects because even though they implement IDisposable, the inner singleton they forward the call onto may not implement IDisposable. If I could fix this problem I could reduce the time to call Dispose to almost nothing.

  3. #3
    Join Date
    Jul 2010
    Posts
    245

    Default

    This is an interesting approach to increasing the disposal performance; would you be willing to submit a github pull request that we could examine? This (general) issue is probably related to https://jira.springsource.org/browse/SPRNET-1318 and we are aware that the present dispose algorithm is a possible performance bottleneck and would be interested in seeing your approach to solving it if you're willing to share it.

  4. #4
    Join Date
    Jun 2007
    Posts
    17

    Default Potential fix

    The notes in the defect you referenced talk about a more appropriate fix -- using separate factories to track destroy-able objects. Unfortunately, the fix I came up with (below) partially relies on hard coding a factory type -- a hack if you will -- that isn't worthy of submission. Here's what I experimented with (instrumentation removed for clarity):

    protected override void DestroyObject(string name, object target)
    {
    if (target is IDisposable)
    {
    ObjectFactoryCreatingFactoryObject factory = target as ObjectFactoryCreatingFactoryObject;
    // destroy factory only if it requires it
    if (factory != null && factory.IsSingleton && !(factory.GetObject() is IDisposable))
    return;

    DestroyDependantObjects(name);

    ((IDisposable)target).Dispose();
    }
    else
    {
    RootObjectDefinition rootDefinition = GetMergedObjectDefinition(name, false);
    if (rootDefinition != null && StringUtils.HasText(rootDefinition.DestroyMethodNa me))
    {
    DestroyDependantObjects(name);
    InvokeCustomDestroyMethod(name, target, rootDefinition.DestroyMethodName);
    }
    }
    }

  5. #5
    Join Date
    Jul 2010
    Posts
    245

    Default

    Understood -- thanks for the sample code all the same. Bottom line: we know about this bottleneck and are targeting to address it in the next release. Thanks again!

  6. #6
    Join Date
    Mar 2012
    Posts
    2

    Default

    We just ran into the same issue when creating more than a few hundred objects. I ran a test on some simple objects with spring creating (10K) and "disposing" of them took over 10 minutes on a really nice machine.

    I am not trying to "rub salt" on the wound since you guys already know about the issue.

    I just was checking on the status of this. I saw the target for the release had passed.

    Maybe some other alternatives that would be okay to use and faster to code would be:

    1. Like the previous post - disable Idisp checks from a flag in the xml file... no need to do the check if you know you are not using any class the imps Idisposable.

    2. Having a marker interface for parent classes that you want to dispose of - that might hold or "own" Idisposable objects.

    3. Separate thread?

    Thanks,
    Brad

  7. #7
    Join Date
    Mar 2012
    Posts
    2

    Default

    I just wanted to update what we did to resolve the issue for us.

    1. We are not using any class that imps IDisposable but we might in the future, and other groups at work use our spring dll.

    2. I tried the threaded approach and it worked, but the performance in Unity3d was awful - Unity does not like threads (uses - co-routines).

    3. I ended up writing and injecting a custom object that implements IObjectPostProcessor.

    <snip>
    public object PostProcessAfterInitialization(object instance, string objectName)
    {
    if (instance is IDisposable)
    {
    _warnings.Add("WARNING -> you are instantiating a clas that implements IDisposable. Potential resource leak if you are skipping the Dispose check. Class-> " + instance + " name->" + objectName);
    }
    return instance;
    }

    </snip>

    I store a generic list of warnings(string) that is then transfered over to the Unity console window....

    4. Then in public abstract class AbstractApplicationContext
    ...
    private const string IGNORE_IDISPOSABLE = "Ignore_IDisposable";
    public event EventHandler<XXXSpringEventArgs > OnWarning = delegate { };

    public virtual void Dispose()

    ...
    if (!ContainsObjectDefinition(IGNORE_IDISPOSABLE))
    {
    ObjectFactory.Dispose();
    }
    else
    {
    /// XXX = removed name of company where I work.

    XXXSpringEventArgs e = new XXXSpringEventArgs ();
    e.Warning = "Skipping disposing of Idisposable objects if they exist.";
    OnWarning(this, e);
    }
    ...

    4. Then in our spring xml file.. we inject our class that imps IObjectPostProcessor (see #3).

    <!-- To ignore IDisposable due to spring scaling. -->
    <object name="Ignore_IDisposable" type="Spring.Context.Support.OurCustomSpringPostPr ocessor"/>



    All in all, the resolution I came up with is similar to the one above. However, if you don't do anything with my approach, spring will act like normal. You have to actually inject a custom class
    to get the custom actions. I guess it is a hybrid of one of the options I suggested in my last post - sort of a marker interface, but not really.


    BD
    Last edited by bdunn13; 03-27-2012 at 05:45 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •