LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Memory Growth Issues in LabVIEW

I am encountering a memory growth issue while running my LabVIEW program. As the program executes, the memory usage (as monitored by task manager) keeps increasing until the program eventually crashes.

Program Overview:

  1. Move the motorized stage to a specific position.
  2. Measure data (100 averages).
  3. Plot each point
  4. Repeat the measurement for scanning across different X positions.

Troubleshooting Attempts:

  • Initializing shift register data before each loop iteration.
  • Closing the motor connection after each movement.
  • However, none of these effectively resolved the issue.

I have attached an image showing the main parts of my program.

If anyone has insights or suggestions on how to efficiently manage memory, I would greatly appreciate your advice.

 

 

 

salsberry_3-1739331090200.png

 

salsberry_1-1739331017422.png

salsberry_2-1739331033905.png

salsberry_4-1739331105184.png

 

 

0 Kudos
Message 1 of 10
(240 Views)

Can you please tell us about your environment and your experience?  You've been a member of the Forum for eight years, but you have only two posts, both this month.

 

Looking at your code, I see everything in Sequence fences.  Is this FPGA code?  If you've been reading this Forum for eight years, you'll know that "pictures" are not an easy way for us to examine "large" Block Diagrams.

 

To help us help you, please provide the following:

  • The version of LabVIEW you are using (I'm guessing LabVIEW 2021), and any significant "environments" you are using (such as LabVIEW Real-Time and LabVIEW FPGA?).
  • A description of the hardware that this code supports (the source of the data you are saving).
  • If you could make a "small" Project that includes the code you are using and enough "support stuff" (such as TypeDefs, and the Project (.lvproj) file) that the code can be examined without any "blank VIs with a big Question Mark" inside them.
  • For now, your Demo code does not need to actually do any file I/O -- you can simulate it by providing "File Write.vi" function that simply accepts your data packet and does nothing with it (call it a "Assume Write to File Goes Here").

Are you using anything like a Producer/Consumer design to handle the Data I/O?  What is your data rate?  How are the data getting from the "Generation" part of the code to the "Save It Away" part?  We (and by "we", I mean "I", at least) really need to see real code on a real screen that I can move around to "see it all") to help you figure this out.

 

Bob Schor

0 Kudos
Message 2 of 10
(231 Views)

Dear Bob_Schor,

 

Thank you for your response.

I initially signed up for the forum when I was an undergraduate, but I haven’t actively used LabVIEW for a long time. Recently, however, it has become essential for my measurements, so I am working on improving my understanding.

 

I would consider myself a beginner in LabVIEW. I am familiar with basic structures such as for loops, mathematical operations, file read/write functions, and integrating subVIs from measurement devices (e.g., SR830, Keithley, etc.). However, I lack in-depth knowledge of more advanced topics like the ones you mentioned.

 

Before attaching my actual code, I have a few additional questions:

  1. My LabVIEW version includes the FPGA module, but I am unsure whether I am actually using that functionality. How can I verify this?
  2. I am using Thorlabs Kinesis KCube for motorized stage control and collecting data from SR830 via a DAC converter.
  3. Since my program contains multiple subVIs, how should I properly save and attach my code as a LabVIEW project so that it opens correctly on another system?
  4. I believe I can modify my code to use the "File Write.vi" function as a placeholder for file I/O.
  5. The data sampling rate is 10 kHz, and I acquire 600 data points, average them within a for loop, and then store the result in a shift register.

I appreciate your guidance, and I will attach the real code once I understand how to package it correctly.

0 Kudos
Message 3 of 10
(227 Views)

I see lots of .Net nodes, returning references every single time, but not one single Close Node!

Each .Net reference created through a Constructor node or returned as a sub reference by a property or method node, allocates a LabVIEW memory block to maintain the underlaying .Net object reference. If you just let the according wire end in thin air, this object still remains in memory. On the next iteration you create again an object and call nodes that return sub objects and so on. Every .Net refnum NEEDS to be explicitly closed after it is not needed anymore.

 

LabVIEW's managed contract works differently than a .Net contract. It can reuse its own native datatypes on every loop iteration if the compiler has determined with complicated rules that it is not needed anymore but it can NOT determine if that is the case for external resources such a .Net objects.

 

You need to help it with that. LabVIEW only automatically closes any refnum objects when the top level VI stops executing, but your VI keeps running in a loop, so new objects are getting created on every loop iteration but never closed.

 

Most likely you would not need to create new objects and retrieve new subobjects on every loop iteration but that requires a somewhat more structured approach with a real state machine architecture. Your current program is a big spaghetti mess.

Rolf Kalbermatter
My Blog
Message 4 of 10
(192 Views)

Dear Rolf Kalbermatter

 

Thank you for your kind words.

I have simplified the program by using only the .NET reference and a for loop.

I attempted to explicitly close the .NET reference after each loop, but I am still noticing memory growth while the program is running.

I have attached the program for your review. There is no sub VI from other source expect for Kinesis-labview provide by the following URL (Kinesis® with LabVIEW)

Could you kindly take a look and provide any suggestions or improvements to address the memory growth issue?

 

Thank you in advance for your assistance.

 

salsberry_0-1739392448211.pngsalsberry_1-1739392468217.png

 

0 Kudos
Message 5 of 10
(132 Views)

The Close in the red rectangle should not be in there. You should match the number of closes with the number of Constructor nodes, respectively with Property nodes that return a refnum.

 

And the Build array nodes in the yellow rectangles will of course each create an ever growing array!

salsberry_1-1739392468217.png

Rolf Kalbermatter
My Blog
0 Kudos
Message 6 of 10
(124 Views)

@rolfk wrote:

The Close in the red rectangle should not be in there. You should match the number of closes with the number of Constructor nodes, respectively with Property nodes that return a refnum.

 

And the Build array nodes in the yellow rectangles will of course each create an ever growing array!

salsberry_1-1739392468217.png


In addition, each time the local variable "Time Array" runs a copy of the dataset is made. Local Variables create copies, can be okay for scalars, but nor ever growing arrays.

0 Kudos
Message 7 of 10
(106 Views)

Thank you for your previous feedback.

 

I attempted to organize the process as you advised, but I am still observing memory growth and experiencing interval delays during the measurement. I'm not entirely sure if I implemented the changes correctly as per your suggestions.

 

Could you kindly take another look at this and provide further guidance?

 

I appreciate your assistance in advance.

 

salsberry_0-1739422306500.png

salsberry_1-1739422320955.png

 

0 Kudos
Message 8 of 10
(80 Views)

Hi salsberry,

 


@salsberry wrote:

Could you kindly take another look at this and provide further guidance?

 

I appreciate your assistance in advance.


  • Convert the outer sequence into a flat sequence.
  • Replace all locals variables in the sequence frames by wires.
  • use shift registers attached to the loop to hold the arrays like "Time array"…
  • After doing those 3 items you should be able to get rid of sequence frames at all!
  • Where are all those terminals located for your locals? (Cannot open your VI right now as I'm stuck at LV2019.)
  • You SHOULD NOT close references immediately after calling a property node.
    It is COMPLETE NONSENSE to close a reference when you want to use it afterwards!!!
  • You SHOULD enforce dataflow for all the CloseReference nodes by using the error wire!
Best regards,
GerdW


using LV2016/2019/2021 on Win10/11+cRIO, TestStand2016/2019
0 Kudos
Message 9 of 10
(71 Views)

@salsberry wrote:

Thank you for your previous feedback.

 

I attempted to organize the process as you advised, but I am still observing memory growth and experiencing interval delays during the measurement. I'm not entirely sure if I implemented the changes correctly as per your suggestions.

 

Could you kindly take another look at this and provide further guidance?

 

I appreciate your assistance in advance.

 

salsberry_0-1739422306500.png


That's in parts better but in terms of handling those references it is an utter "making matters worse"!

salsberry_0-1739422306500.png

When I said property nodes that return a refnum I did not mean the "duplicate refnum out" terminal but refnums returned in the body of the property or method node (both green nodes do return a refnum as property value).

 

The red Close nodes are all utter nonsense and in fact should make your program fail completely to communicate with your device. The green Close node properly closes the refnum returned by the Device property node, but you just let the refnum from the Create Device method node flow into thin air to be never used and never closed. In fact the Create Device refnum should be already fine, you should not need to retrieve another copy of that just created refnum to use it.

 

The KCube Stepper Control refnum SHOULD NOT be closed in this VI ever. Somewhere you do create that refnum unless its a static .Net reference and that somewhere you should also close it. Proper software design is also about trying to manage resources in a way that they are allocated and deallocated in the same part of your program as much as possible. Don't create it in your startup routine, then try to figure out in which sub part of your program you need to deallocate it. You will soon end up in a complicated

 

if (condition X) but not (condition Y) except when (condition Z) but not (when my cat takes a nap) and (there is full moon)

     deallocate this resource!

 

Still able to understand when it should be done and when not?

Exactly! You can't and neither can I nor do I want to understand.

But by handling allocation (creation) and deallocation in the same logical level of your program, you can avoid this type of involved conditionals almost completely.

 

This means that in this VI you need to close the two references returned by the Create Device method node and the Device property node exactly once each in every iteration, since they got created once. Of course the Device property node is almost certainly unnecessary since you already get a Device refnum to use from the Create Device method.

 

And then comes the next level: Why create a new device in every iteration? This should almost certainly be outside the loop (and the according close refnum too) unless the device driver for your hardware is a total fart from some software programmer who better should have stayed planting potatoes instead.

Rolf Kalbermatter
My Blog
0 Kudos
Message 10 of 10
(58 Views)