LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

.NET - Explicitly closing references for each property/invoke node

Solved!
Go to solution

I know this has been asked before, but I'm still unsure.

 

Suppose I have the following sub VI (which gets information about the available network interfaces).

https://i.imgur.com/2IJB3te.png

 

No ref closing.png

It has many .Net property and invoke nodes which use references from previous .Net nodes.

 

 

Is it best practice to explicitly close these references, or will LabVIEW automatically close them, once the VI has finished running, in a timely fashion ready for garbage collection (main VI still running)?

 

 

If they should be closed, there's then the question of "can I just close the parent reference" (as below)?

https://i.imgur.com/Zk15dP6.png

Parent ref closeParent ref close

Or should all of them be closed individually?

https://i.imgur.com/Y436mO7.png

All refs closedAll refs closed

 

VIs also attached, both 2017 and 2010 versions.



Using LV2018 32 bit

Highly recommended open source screen capture software (useful for bug reports).

https://getsharex.com/
0 Kudos
Message 1 of 14
(5,565 Views)
Solution
Accepted by topic author matt.baker

Is it best practice to explicitly close these references, or will LabVIEW automatically close them, once the VI has finished running, in a timely fashion ready for garbage collection (main VI still running)?

 

Yes, you should close all references, LabVIEW won't do that for you.

 

If they should be closed, there's then the question of "can I just close the parent reference" (as below)?

 

No, that's not a good idea.

 

Or should all of them be closed individually?

 

Yes, that's the correct thing to do!

 

Regards, Jens

Kudos are welcome...
Message 2 of 14
(5,539 Views)
Solution
Accepted by topic author matt.baker

You're not closing objects. You're closing references to objects. An object will be released when the reference count is 0. So not closing child object, might even force the parent to stay open.

 

So closing the parent is not enough. You need to close all references you opened.

 

Note that Close Reference does except arrays. That might help a little bit.

 

>Is it best practice to explicitly close these references,

 

Absolutelly.

 

>or will LabVIEW automatically close them

 

No. Native references: yes, sometimes (or rather the refs will always be the same so it's no problem). .NET, ActiveX references: no.

 

>, once the VI has finished running,

 

Not when the VI finished running, unless it's running top level. LV might release some references when the VI goes to idle, but I wouldn't count on it. It's not good practice.

 

>in a timely fashion ready for garbage collection (main VI still running)?

 

LabVIEW has no garbage collection (although it does a good job pretending it does).

Message 3 of 14
(5,537 Views)

Thanks both for your replies. Very helpful.

 


wiebe@CARYA wrote:

You're not closing objects. You're closing references to objects.


This is the part I keep forgetting.

 

With that in mind, does this mean the order of closing shouldn't matter, as long as they are all closed and not used again?

 

The memory consumed by the .NET object would still be released through the .NET CLR garbage collection though, wouldn't it?



Using LV2018 32 bit

Highly recommended open source screen capture software (useful for bug reports).

https://getsharex.com/
0 Kudos
Message 4 of 14
(5,515 Views)

@matt.baker wrote:

Thanks both for your replies. Very helpful.

 


wiebe@CARYA wrote:

You're not closing objects. You're closing references to objects.


This is the part I keep forgetting.

 

With that in mind, does this mean the order of closing shouldn't matter, as long as they are all closed and not used again?


I'm inclined to say the order doesn't matter. I've never seen it matter, and in theory it shouldn't. (If you'll call some Close or Dispose method's the order will matter).

 


matt.baker wrote

The memory consumed by the .NET object would still be released through the .NET CLR garbage collection though, wouldn't it?


When the object is released by LV, .NET might clean up unreferenced objects. But if LV has a reference to those objects, they will not be unreferenced. So the .NET CLR will not consider them garbage.

 

Message 5 of 14
(5,509 Views)

Just a couple of notes to add:

  1. Objects that are referenced across the CLR COM boundary are pinned by the CLR (so that GC doesn't move them around by accident). This is why you need to indicate when you no longer require a reference to that object "Close Reference"; this will indicate to the CLR that the host no longer requires the reference pinned, making it eligible for collection later.
  2. In 99.9999% of cases, the VI Hierarchy stopping/going idle will cause LabVIEW to indicate to the CLR that all the pinned objects created within that hierarchy are no longer in use and thus result in eventual collection. This is not true if the VI hierarchy is not idle - eg. your SubVI completes but its caller is still executing. There are also some caveats when you call VIs asynchronously - some of the options in LabVIEW for this generate a new VI hierarchy that follows these same rules but it is possible for one hierarchy to stop while another continues; this can cause havoc closing a reference in a hierarhcy depending on which of the hierarchies is the "owner" of the .NET pinned references (you get invalid reference errors).
  3. "Close References" order only matters if you need to perform some sort of manual "close" or "dispose" action prior to completing your activities and the object in question is a wrapper around unmanaged references. Generally such classes should follow the IDisposable pattern and include the dispose hook in the Finalizer for the class (so that GC will call the Finalizer and release that memory for you). If you don't know or can't guarantee that this is the case then just follow the convention provided by the class author.
Message 6 of 14
(5,484 Views)

@tyk007 wrote:

3) "Close References" order only matters if you need to perform some sort of manual "close" or "dispose" action prior to completing your activities and the object in question is a wrapper around unmanaged references. Generally such classes should follow the IDisposable pattern and include the dispose hook in the Finalizer for the class (so that GC will call the Finalizer and release that memory for you). If you don't know or can't guarantee that this is the case then just follow the convention provided by the class author.


You've lost me on this one. So we don't need to close "pure" .NET objects? Do you mean LV automatically disposes objects when "the wire ends"?

0 Kudos
Message 7 of 14
(5,471 Views)

Sorry, the term "close" is overloaded here. What I was trying to say is that the order of when you call "Close References" on your objects (ordering between them) does not matter. For an individual reference however if the class you are using has a defined protocol for how you must indicate you are finished with that object you must follow that prior to calling "Close References" on an instance of it. For some classes this is a "Dispose" or "Close" method; in .NET there is a typical pattern for this (IDisposable) which has a "Dispose" method to help release unmanaged resources that would otherwise leak.

 

LabVIEW still doesn't automatically release references for ".NET objects" (purity aside) automatically until the top-level VI Hierarchy that created that reference goes idle. I believe this is generally the same reasoning as for all other reference-like types in LabVIEW (as mentioned here http://www.ni.com/tutorial/14393/en/).

 

So if I was still able to edit my post I would say:

 

  1. Objects that are referenced across the CLR COM boundary are pinned by the CLR (so that GC doesn't move them around by accident). This is why you need to indicate when you no longer require a reference to that object "Close Reference"; this will indicate to the CLR that the host no longer requires the reference pinned, making it eligible for collection later.
  2. In 99.9999% of cases, the VI Hierarchy stopping/going idle will cause LabVIEW to indicate to the CLR that all the pinned objects created within that hierarchy are no longer in use and thus result in eventual collection. This is not true if the VI hierarchy is not idle - eg. your SubVI completes but its caller is still executing.
  3. Order of "Close References" does not matter as long as you are finished with the object
  4. If the specific class you are using has a defined protocol for how you indicate that you are finished with any resources it has (eg. a "Dispose() method or similar as defined by the author of the class) then you should follow this protocol prior to performing "Close References" on the reference.
  5. References to "static" .NET objects do not technically need to be closed (by definition there is only ever a single instance per AppDomain and only ever gets collected when that AppDomain is destroyed aka application exit) but it is good practice (and habit) to do so anyway.
  6. Be careful about sharing .NET objects across VI Hierarchies since when the VI Hierarchy that created a reference goes idle, that reference is automatically closed. This is only a concern when calling certain LabVIEW async nodes that create new VI hierarchies (refer to this for examples of said nodes http://www.ni.com/tutorial/14393/en) and you want to share .NET objects between them.

 Does that make more sense? I did sneak a 5th/6th one in there just for completeness.

0 Kudos
Message 8 of 14
(5,449 Views)

@matt.baker wrote:

With that in mind, does this mean the order of closing shouldn't matter, as long as they are all closed and not used again?

In theory yes, in practice there are buggy .Net assemblies out there which hand out "property" objects to the caller without those objects referencing their owner in any proper way but still maintaining some pointers that are owned by the owner. Releasing the owner before the owned object could then mean that the the owned object tries to reference something in the owner which has already vanished from memory. So I make it a rule to always close ActiveX and .Net objects in the reverse order in which I obtained them.

 

The memory consumed by the .NET object would still be released through the .NET CLR garbage collection though, wouldn't it?


Nope! As long as there is a reference to an object open the .NET CLR garbage collecter is required to not touch that object or REALLY BAD THINGS start to happen. In ActiveX you don't even have a garbage collector. Objects deallocate themselves as soon as the reference count reaches 0.

 


wiebe@CARYA wrote:

 

Not when the VI finished running, unless it's running top level. LV might release some references when the VI goes to idle, but I wouldn't count on it. It's not good practice.

Actually LabVIEW closes all refnum types when the top level VI in whose hierarchy the refnum was created goes idle. You only can disable that for VISA refnums in the options (yes the purple tag based (named) refnums like VISA and IMAQ too are also refnums).

But I make it a rule to not rely on that but instead close all refnums explicitly. Your object may be called in a way that simply releases its refnum automatically later on as your dynamically started deamon terminates but in 6 months from now you pull that VI library out of your "awsome program" and use it in your "totally awsome super program" using it in a way that creates those objects over and over again in a hierarchy that never goes idle and everything works fine during development and debugging but starts to explode badly once you deployed the app to a remote station in Antarctica after two months of continuously creating .Net objects without them ever being released!

Rolf Kalbermatter
My Blog
Message 9 of 14
(5,428 Views)

There is a pragmatic approach:

 

Run the VI in a while loop (not continuous run).

Does the memory increase?

More references to close!

Message 10 of 14
(5,420 Views)