February 2007

Sun Mon Tue Wed Thu Fri Sat
        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28      
Blog powered by TypePad

« Chaos and Order | Main | What is a Service Dog? »

How to say goodbye to your Refnum

Refnums in LabVIEW are not a new thing - they represent some external resource that must be tracked and released when you're finished with it. The most common example is the file refnum, created whenever you open a file.

For those programming .NET in LabVIEW, refnums are your constant companion. We convert what .NET data types we can into native types, but there are simply too many types in .NET that have no correlation. So, you get refnums.

But, just like files, you need to be sure to close the refnum when your done with it, or you'll get a memory leak. Let's take a look at when you do and don't need to close a .NET refnum.
To help explain the rules, I'm going to refer to the image you see here on the page. It's got several examples that I hope demonstrate the do's and don'ts.Leak_1

Let me start with the basic rule - if a .NET object is put onto a wire for the first time (as far as LabVIEW is aware of), then it generates a new refnum. If it's a new refnum, it needs to be closed.

So, lets look at the first and second examples. Here is a very simple bit of code that creates a .NET object via the constructor node. Obviously, if you create an object, its refnum needs to be closed (as shown). Notice that the code also calls a method (GetType) which returns another .NET object. In the first example, however, we don't close that refnum. Why? Because LabVIEW detects that it's never used - no wire is connected to the terminal. In that case, we can handle the cleanup automatically. But, as the second example shows, once you've wired it, you need to close it.

The next example is one of a pattern that often has memory leaks in it. In this case, you're iterating through the elements in an object via a .NET enumerator. The most common mistake is to forget to close reference returned from Current.

The next two show actual memory leaks - probably the most common type I've seen. Because many .NET objects are simply returned from one call, only to be passed into another, it's easy to forget that they need to be closed. The refnum from GetType is on a wire for the first time, so according to the rule, must be closed. Same with the static property, CurrentDomain. The fact that they only travel a few millimeters doesn't matter :)

The last example shows the corollary to the rule - when it's known to LabVIEW that it isn't a first time object. Consider a cast of an object from one type to another. For .NET, we provide a couple of nodes that convert a refnum type definition from one type to another - but we know that's what we are doing. We, meaning LabVIEW, are well aware that the actual object going into the left terminal is the same one coming out the right side. It's a cast operation after all. Therefore, you don't need to close both types of refnums. If you were to drop down probes on the refnum before and after, you'd see that the value of the refnum was the same on each side - a good indication that it's the same one.

So, there you go...hopefully some simply guidelines to know when to close the refnum. The good news is that we track all refnums internally, so when your application stops running, we'll clean up after any leftover refnums. But if your application is long running, you may run out of memory before then - so be careful.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83424ed4953ef00d834bdfc2869e2

Listed below are links to weblogs that reference How to say goodbye to your Refnum:

Comments

Hello,

nice documentation!

I asume that most of us already made our own experiences with that sort of LabVIEW - .NET issue.
In other words: I'd have expected to see this great explanation some months(year) earlier.

Is there an understandable reason for the fact that we have to close these unused refnums our own? At first I thougth that these handles are garbage collected when they become invalid (when the function that uses this refnum ends execution) as it happens in other .NET environments.

Thanks, Sebastian

First off - I'm glad that this was helpful. If you have other areas that you'd like to see covered, please let me know.

Second, the reason that you need to close the refnums is that LabVIEW is not a garbage collection (GC) system.

To ensure that the .NET object stays around as long as you'll need it, we tell the .NET GC that we're an external reference (via a GCHandle) and thus the object won't be GC'ed until we release that reference.

Again, LabVIEW does track all of these references, but the only time we know it's safe to release them is when all the VI stop executing - and that means long running applications need to be careful.

Hope that helps clear it up.

Thanks,Brian that sounds reasonable to me!

I just feel into about every error you listed (except the constructor/close one). I assumed closing any refnum would cause issues with .NET and GC, but the assumption was in the wrong direction.

I wanted to add one additional note for 7.1 users (this is fixed in 8+): If the refnum wired is branched anywhere, and the branch is not closed, the the ref (and hance the GCHandle) sticks around. All branches of refnum wires must be closed. In 8+ it seems that any usage of a closed refnum that was previously branched will through a 1172 exception. This seems to be the correct way to implement this. Unfortunately, my project is stuck on 7.1 and not upgrading. But thanks for this blog entry. Saved me a lot of time.

Typo: I meant "fell" into every error.

I'm glad the post is coming in handy. I know when I started in LabVIEW near the end of LV 8's development, I was confused myself on the rules and basically discovered the above "facts" by code review and a debugger. :)

I haven't gone back to look at LV 7 code, but I'm surprised to hear what you said about the branching wire. I don't believe that is the case - branching the wire creates a copy of the data on the wire - the refnum itself - but it shouldn't create a new refnum. Do you have a test VI that shows this behavior? If so, please mail it to me.

I am very new in using Labview. I made .Net program and I want to use the methods from DLL generated by .Net framework in labview. I tried to follow the way given on NI website but I am not able to see any method. Can anybody please send me small .Net program which has one public method that I can see and use in labview environment.

Thank you

The easiest thing is to try to call something from the .NET framework itself. For example, you can drop down a constructor node and then scroll down to the System assembly. Then select the System.UriBuilder class. This has several nice methods and properties that build up URLs or display their parts. I like it as a beginners point since it's almost all simple strings.

Hi,

In response to a discusion on the NI forum (http://forums.ni.com/ni/board/message?board.id=170&message.id=324051&requireLogin=False ), I just like to let everybody know that everything told here also applies to ActiveX references.

I didn't know that references without a wire don't need to be closed...

Thanks,

Wiebe.

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment