Author Topic: Fenton Webb's advice re "To dispose or not to dispose"  (Read 75370 times)

0 Members and 1 Guest are viewing this topic.

pkohut

  • Bull Frog
  • Posts: 483
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #45 on: August 08, 2012, 04:26:25 AM »
Money on Evgeniy.
New tread (not retired) - public repo at https://github.com/pkohut

pkohut

  • Bull Frog
  • Posts: 483
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #46 on: August 08, 2012, 04:28:39 AM »
It should go without mention, that any solution must be pure LISP, and may not depend on any external API calls or any undocumented APIs.

Definitely on Evgeniy.
New tread (not retired) - public repo at https://github.com/pkohut

TheMaster

  • Guest
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #47 on: August 08, 2012, 04:36:27 AM »

Hey TT, What you say is totally true, but as I have mentioned before, AutoCAD is *not* thread safe, meaning that if you allow the GC to dispose of AutoCAD objects you run the risk of some AutoCAD code being executed on something otherthan the main thread, which it was never designed for - try it and see what happens - how many of you out there get random crashes happening that you cannot track down...? If you insist on allowing the GC to dispose your AutoCAD class objects, be sure to utilize my blog entry on gcConcurrent - that's my advice.


I think you misunderstood me  :wink:

We already know that managed wrappers whose finalizers execute code that's not thread safe, absolutely must be disposed of determinstically, or kaboom, so I wasn't referring to those cases, but rather the cases where Dispose() is unnecessary and/or pointless, the main one being database-resident DBObjects obtained from a transaction.  If you don't dispose them, their finalizers will run on the GC's thread, on another CPU core, and will have no impact on the performance of the code that uses those managed wrappers. 

I really don't agree with the advice regarding disabling concurrent garbage collection because that requires the application to wait for it to occur, and I seriously doubt you've investigated what kind of effect a GC can have during user-interactive operations like dragging, and so forth. Covering up a problem in way that impacts performance application-wide is not a professionally-responsible way of dealing with bugs (e.g., failure to Dispose() something).  If it is done only as a temporary stopgap measure, then fine, but otherwise, slowing down their application is not a legitimate solution.


ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #48 on: August 08, 2012, 04:36:45 AM »
I do not want to disclose the details to a rival.
But I am sure I will not go to the trick. My solution you are satisfied!

TheMaster

  • Guest
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #49 on: August 08, 2012, 05:36:17 AM »
I do not want to disclose the details to a rival.
But I am sure I will not go to the trick. My solution you are satisfied!

Details?

As in AutoCAD Core Console?


ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #50 on: August 08, 2012, 05:57:08 AM »
I do not want to disclose the details to a rival.
But I am sure I will not go to the trick. My solution you are satisfied!

Details?

As in AutoCAD Core Console?

It does not matter!
all the algorithms, calculations, logic, will only AutoLISP / Visual LISP!

Do not think that the present results in other languages ​​are invincible!
If you do measurements only of the calculations, the LISP competitive.

I am thankful that you gave me enough time to prepare.  :-)

owenwengerd

  • Bull Frog
  • Posts: 451
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #51 on: August 08, 2012, 09:57:10 AM »
Evgeniy may win the battle, but native code will always win the war. Nevertheless, I'd buy tickets to see this one!

LE3

  • Guest
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #52 on: August 08, 2012, 10:03:39 AM »
... I'd buy tickets to see this one!

+1

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #53 on: August 08, 2012, 10:04:14 AM »
USA USA USA USA USA USA
.......
Tony is American?
 
 
I'll thrown down for Tony.
 

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #54 on: August 08, 2012, 10:09:06 AM »
Losing team has post all code in VB for a month, with Option explicit and strict off?

BlackBox

  • King Gator
  • Posts: 3770
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #55 on: August 08, 2012, 10:44:21 AM »
Losing team has post all code in VB for a month, with Option explicit and strict off?

... Way to rock out with your nerd out, Jeff!  :-P



 :lmao:
"How we think determines what we do, and what we do determines what we get."

fentonwebb

  • Guest
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #56 on: August 08, 2012, 10:50:07 AM »

Hey TT, What you say is totally true, but as I have mentioned before, AutoCAD is *not* thread safe, meaning that if you allow the GC to dispose of AutoCAD objects you run the risk of some AutoCAD code being executed on something otherthan the main thread, which it was never designed for - try it and see what happens - how many of you out there get random crashes happening that you cannot track down...? If you insist on allowing the GC to dispose your AutoCAD class objects, be sure to utilize my blog entry on gcConcurrent - that's my advice.


I think you misunderstood me  :wink:

We already know that managed wrappers whose finalizers execute code that's not thread safe, absolutely must be disposed of determinstically, or kaboom, so I wasn't referring to those cases, but rather the cases where Dispose() is unnecessary and/or pointless, the main one being database-resident DBObjects obtained from a transaction.  If you don't dispose them, their finalizers will run on the GC's thread, on another CPU core, and will have no impact on the performance of the code that uses those managed wrappers. 

I really don't agree with the advice regarding disabling concurrent garbage collection because that requires the application to wait for it to occur, and I seriously doubt you've investigated what kind of effect a GC can have during user-interactive operations like dragging, and so forth. Covering up a problem in way that impacts performance application-wide is not a professionally-responsible way of dealing with bugs (e.g., failure to Dispose() something).  If it is done only as a temporary stopgap measure, then fine, but otherwise, slowing down their application is not a legitimate solution.

Hey TT,

it happens 8-)

I agree with everything you say above.

In addition to your last paragraph, as I said in my blog, "Now, say you are at a customer site where they are experiencing random crashes with your app, or you are running behind schedule and just can’t seem to find the place where the random crash is happening then here’s a quick fix for you – try forcing the GC to run on the Main Thread…"

MexicanCustard

  • Swamp Rat
  • Posts: 705
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #57 on: August 08, 2012, 11:11:48 AM »


... Way to rock out with your nerd out, Jeff!  :-P

 :lmao: :lmao: :lmao:

This was a shameless posts just to put my total posts over 200 and not be a newt anymore.
Revit 2019, AMEP 2019 64bit Win 10

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #58 on: August 08, 2012, 12:09:09 PM »
Masters games in perspective: Fenton / Tony, Evgeny / Tony.
All this may be far away from my level...

Back to the main thread, I'm still confused: Fenton said white, Tony said black...

So I tried my own tests inspired by the way shown in the "The Stephen and Fenton Show: ADN DevCast Episode 2" about Disposing. I run the code (reply #21) after removing disposing statements (plineCollection disposing, regionCollection disposing, each region disposing, and combinations...).

It appears that it's only when I do not dispose each region one by one that the Visual Studio stack windows shows:
"Forgot to call Dispose? (Autodesk.AutoCAD.DatabaseServices.Region): DisposableWrapper"

It looks like Tony was right, disposing the DBObjectCollection doesn't dispose the DBObject it contains for which a managed wrapper have been created.
And it seems that if the DBObjectCollection contains only database-resident objects (plineCollection) or is entirely iterated creating managed wrappers (regionCollection), it do not need to be disposed (none alert from VS in these cases).
Speaking English as a French Frog

TheMaster

  • Guest
Re: Fenton Webb's advice re "To dispose or not to dispose"
« Reply #59 on: August 08, 2012, 02:06:24 PM »
And it seems that if the DBObjectCollection contains only database-resident objects (plineCollection) or is entirely iterated creating managed wrappers (regionCollection), it do not need to be disposed (none alert from VS in these cases).

Right, but since you're working with a collection (usually using some type of loop where you operate on each item), a best practice is to always dispose the DBObjectCollection, preferably with a using() block, or try/finally, because that ensures it will not delete any unprocessed AcDbObjects in the collection on the GC's thread if your code exits prematurely as a result of an exception.

The DisposableList<T> helper class shown below simplifies the problem of ensuring that  multiple IDisposables are all disposed determinstically:

Code - C#: [Select]
  1.  
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. /// DisposableList<T> class
  8. /// Copyright (c) 2012  Tony Tanzillo
  9.  
  10. namespace System.Collections.Generic
  11. {
  12.  
  13.    /// DisposableList is a specialization of System.Collections.Generic.List<T> that
  14.    /// stores and manages elements that implement the IDisposable interface.
  15.    ///
  16.    /// The main purpose of DisposableList is to gurantee that all items in the list
  17.    /// are disposed when the list is disposed, deterministically, even if a call to
  18.    /// any item's Dispose() method throws an exception.
  19.    ///
  20.    /// Note that DisposableList<T> does not supress exceptions raised by calls to the
  21.    /// Dispose() method of any item, it merely ensures that any remaining 'undisposed'
  22.    /// items are disposed before the exception propagates up the call stack.
  23.    ///
  24.    /// Use DisposableList<T> exactly as you would use its base type, and when you want
  25.    /// all contained elements disposed, call it's Dispose() method.
  26.    ///
  27.    /// Using DisposableList<T> with a DBObjectCollection:
  28.    ///
  29.    /// DisposableList can be handy when working with DBObjectCollections containing
  30.    /// DBObjects that are not database-resident. It helps to ensure that if your code
  31.    /// fails before all items retreived from the collection are processed, those items
  32.    /// will be determinstically disposed, and will not have their finalizer's called
  33.    /// on the GC's thread, which could lead to a fatal error that terminates AutoCAD.
  34.    ///
  35.    /// In addition, because DisposableList is a strongly-typed collection, you can
  36.    /// avoid repetitively casting items to the type you need to work with, and can
  37.    /// more easily use the contents with LINQ.
  38.    ///
  39.    /// For example, you can pull all the items out of a DBObjectCollection from a
  40.    /// call to the DisposableList's constructor overload that takes an untyped
  41.    /// System.Collections.IEnumerable, and subsequently work exclusively with the
  42.    /// the DisposableList rather than the DBObjectCollection:
  43.    ///
  44.    ///    using( DBObjectCollection items = myCurve.GetSplitCurves(...) )
  45.    ///    using( DisposableList<Curve> curves = new DisposableList<Curve>( items ) )
  46.    ///    {
  47.    ///       // Work with each Curve in the curves list.
  48.    ///       // Once control leaves this using() block, all
  49.    ///       // items in the curves list will be disposed.
  50.    ///    }
  51.    ///
  52.  
  53.    public class DisposableList<T> : List<T>, IDisposable
  54.       where T : IDisposable
  55.    {
  56.       bool disposed = false;
  57.  
  58.       /// <summary>
  59.       ///
  60.       /// If true, contained items are disposed of in reverse order
  61.       /// (last to first). Otherwise, items are disposed in the order
  62.       /// they appear in the list.
  63.       ///
  64.       /// </summary>
  65.  
  66.       bool ReverseOrderedDispose
  67.       {
  68.          get;
  69.          set;
  70.       }
  71.  
  72.       public DisposableList()
  73.       {
  74.       }
  75.  
  76.       public DisposableList( int capacity )
  77.          : base( capacity )
  78.       {
  79.       }
  80.  
  81.       public DisposableList( IEnumerable<T> collection )
  82.          : base( collection )
  83.       {
  84.       }
  85.  
  86.       public DisposableList( System.Collections.IEnumerable collection )
  87.          : base( collection.Cast<T>() )
  88.       {
  89.       }
  90.  
  91.       public void Dispose()
  92.       {
  93.          Dispose( true );
  94.       }
  95.  
  96.       protected virtual void Dispose( bool disposing )
  97.       {
  98.          bool flag = this.disposed;
  99.          this.disposed = true;
  100.          if( disposing && !flag )
  101.          {
  102.             if( this.ReverseOrderedDispose )
  103.                base.Reverse();
  104.             using( IEnumerator<T> e = base.GetEnumerator() )
  105.                DisposeItems( e );
  106.          }
  107.       }
  108.  
  109.       private void DisposeItems( IEnumerator<T> e )
  110.       {
  111.          while( e.MoveNext() )
  112.          {
  113.             try
  114.             {
  115.                T item = e.Current;
  116.                if( item != null )
  117.                   item.Dispose();
  118.             }
  119.             catch
  120.             {
  121.                DisposeItems( e );
  122.                throw;
  123.             }
  124.          }
  125.       }
  126.    }
  127. }
  128.  
  129.  
« Last Edit: August 08, 2012, 03:10:14 PM by TT »