Ernest Galbrun Posted May 2, 2009 Report Share Posted May 2, 2009 Hello, I would like to have some insight about a memory management issue I encountered recently : I am using LVclass to make some treatment on a data set. The data is constituted of a 2D SGL array whose size may be a few millions of elements. I have been quite surprised to see that, every time I called a method of the said class, the corresponding vi remains in memory. The only way I could found to free the memory was to do it manually. However, I don't understand why it is not done automatically. This memory issue is true for every method I end up using in my program, even the simplest one (multiply the array by a scalar constant). Quote Link to comment
Aristos Queue Posted May 3, 2009 Report Share Posted May 3, 2009 Hello, Ernest. I am the lead architect for the OO features. I do not understand your questions, in particular these two lines:QUOTE I have been quite surprised to see that, every time I called a method of the said class, the corresponding vi remains in memory. QUOTE The only way I could found to free the memory was to do it manually. In the first, if a VI calls a subVI, the subVI typically stays in memory. Why do you think there would be any difference in behavior if the subVI is a member of a class? Could you be more explicit about the unexpected behavior you are observing and why it is unexpected? In the second, LV doesn't have a "delete" or "freemem" command, so I am not sure to what you are referring. Could you describe this manual method that you're using? Quote Link to comment
ShaunR Posted May 3, 2009 Report Share Posted May 3, 2009 QUOTE (Aristos Queue @ May 2 2009, 03:40 PM) In the second, LV doesn't have a "delete" or "freemem" command, so I am not sure to what you are referring. Could you describe this manual method that you're using? The Request Deallocation function might be of use here QUOTE When a top-level VI calls a subVI, LabVIEW allocates a data space of memory in which that subVI runs. When the subVI finishes running, LabVIEW usually does not deallocate the data space until the top-level VI finishes running or until the entire application stops, which can result in out-of-memory conditions and degradation of performance. Use this function to deallocate the data space immediately after the VI completes execution. Quote Link to comment
Aristos Queue Posted May 4, 2009 Report Share Posted May 4, 2009 QUOTE (ShaunR @ May 2 2009, 09:50 AM) The Request Deallocation function might be of use here A) Known issue: in LV8.2, 8.5 and 8.6, the Request Dealloc prim does not affect allocations of LV class objects. So any objects allocated in the dataspace of VIs -- not just member VIs, but any VIs -- will not be deallocated by the prim. That does not mean they are leaked. We simply leave the allocations in place. This bug will be fixed in the next release of LV. (It is not listed on the official Known Issues page because it was discovered relatively recently. This prim is very rarely used, as demonstrated by the fact that it took 3 versions of LV before anyone noticed it wasn't having any effect.) B) Using this primitive often creates more problems than it solves performance-wise. I have a strong suspicion that it would not be desirable to use this even if it did affect LV class instances. Besides, Ernest already found some manual mechanism that he tried... I'm curious what that mechanism is. I think we need to know that before we can recommend solutions to the problem he is seeing. If he really does want the entire VI to leave memory, for example, the Request Dealloc prim is not the solution. Quote Link to comment
ShaunR Posted May 4, 2009 Report Share Posted May 4, 2009 QUOTE (Aristos Queue @ May 2 2009, 11:52 PM) A) Known issue: in LV8.2, 8.5 and 8.6, the Request Dealloc prim does not affect allocations of LV class objects. So any objects allocated in the dataspace of VIs -- not just member VIs, but any VIs -- will not be deallocated by the prim. That does not mean they are leaked. We simply leave the allocations in place. This bug will be fixed in the next release of LV. (It is not listed on the official Known Issues page because it was discovered relatively recently. This prim is very rarely used, as demonstrated by the fact that it took 3 versions of LV before anyone noticed it wasn't having any effect.)B) Using this primitive often creates more problems than it solves performance-wise. I have a strong suspicion that it would not be desirable to use this even if it did affect LV class instances. Besides, Ernest already found some manual mechanism that he tried... I'm curious what that mechanism is. I think we need to know that before we can recommend solutions to the problem he is seeing. If he really does want the entire VI to leave memory, for example, the Request Dealloc prim is not the solution. I disagree. IF it worked as it says on the tin (or labview help in this case), this is exactly the scenario where you would use it. Says nothing in the help that it won't work on classes (and they ARE vi's so it should, as in I would see that as a bug too). A slight performance hit using it is better than using up so much memory that you start using the swap file which would be even worse. His problem is plain to me. Large data set remains in memory when not needed. I'm guessing that invoking the the properties and methods also creates copies of that data which remain in memory. I personally would have used a database to store the data and a class accessor to manipulate it (if I used classes...lol) but each to his own. So when's 8.6.2 out?. Quote Link to comment
Aristos Queue Posted May 5, 2009 Report Share Posted May 5, 2009 QUOTE (ShaunR @ May 3 2009, 03:37 AM) I disagree. IF it worked as it says on the tin (or labview help in this case), this is exactly the scenario where you would use it. Says nothing in the help that it won't work on classes (and they ARE vi's so it should, as in I would see that as a bug too). A slight performance hit using it is better than using up so much memory that you start using the swap file which would be even worse. Setting aside the bug with LV classes, the primitive DOES work the way it says in the LV help. That's the problem. A "slight performance hit" would be putting it mildly. For very simple VIs, that primitive can introduce slowdowns of hundreds of percent, and for complex VIs, it can be significantly more. If a user is having problems with too much memory usage in his/her LabVIEW application, there are many things I would suggest he/she attempt before trying that primitive. It is, in fact, dead last on my list of solutions to consider. Don't misunderstand me -- there are situations where it is the right solution. But those situations are rare.QUOTE His problem is plain to me. Large data set remains in memory when not needed. I'm guessing that invoking the the properties and methods also creates copies of that data which remain in memory. And although you might be correct in your diagnosis, I would like to hear confirmation of that from Ernest. And even if you are correct in that there is a large data allocation somewhere that is being copied too often, you have no evidence that it has anything to do with LV classes other than that it happens to be occurring while running one of the member VIs. Problems with large waveforms, strings or arrays can appear in many places. I get multiple bug reports each week assigned to my team that something is wrong with LV classes simply because there's a member VI somewhere in the VI hierarchy without anyone doing any analysis of where the problem is truly coming from. Quote Link to comment
ShaunR Posted May 5, 2009 Report Share Posted May 5, 2009 QUOTE (Aristos Queue @ May 4 2009, 02:02 AM) And although you might be correct in your diagnosis, I would like to hear confirmation of that from Ernest. Ummm. Maybe it had something to do with this statement from Ernest. QUOTE (Ernest Galbrun) The data is constituted of a 2D SGL array whose size may be a few millions of elements. Quote Link to comment
Aristos Queue Posted May 5, 2009 Report Share Posted May 5, 2009 QUOTE (ShaunR @ May 4 2009, 04:19 AM) Ummm. Maybe it had something to do with this statement from Ernest. Ok, he has a large data structure somewhere. But why is that structure being duplicated? Is he legitimately running out of memory because he is updating that structure using local variables? Has he drawn some wire branch such that LV cannot inplace one copy of the data all the way through his program? Quote Link to comment
ShaunR Posted May 5, 2009 Report Share Posted May 5, 2009 So does invoking a property or method cause Labview to copy the data in an object? Or is it all pointer arithmatic. Quote Link to comment
Aristos Queue Posted May 6, 2009 Report Share Posted May 6, 2009 QUOTE (ShaunR @ May 4 2009, 03:17 PM) So does invoking a property or method cause Labview to copy the data in an object? Or is it all pointer arithmatic. When it needs a copy, it makes a copy. When it does not it does not. An easy example -- if you unbundle data from one object and bundle it into another object, clearly a copy is made along the way. If you unbundle using the Inplace Element Structure, modify the value and then put the value right back into the object using the bundle node on the other side of the structure, no copy is made. Quote Link to comment
Ernest Galbrun Posted May 7, 2009 Author Report Share Posted May 7, 2009 QUOTE (Aristos Queue @ May 2 2009, 04:40 PM) Hello, Ernest. I am the lead architect for the OO features. I do not understand your questions, in particular these two lines: In the first, if a VI calls a subVI, the subVI typically stays in memory. Why do you think there would be any difference in behavior if the subVI is a member of a class? Could you be more explicit about the unexpected behavior you are observing and why it is unexpected? In the second, LV doesn't have a "delete" or "freemem" command, so I am not sure to what you are referring. Could you describe this manual method that you're using? First of all, sorry for my long silence, I have broken my clavicle last sunday and they wouldn't tell me their wifi access code in the hospital. Anyway, I must have misunderstood the help section about memory management : "vi memory" is not "front panel memory" from what I understand, and it is front panel memory that is automatically freed when the vi is left ? To answer your question, I have not checked if the behavior is the same when not using LVclasses, I just figured that it was probably linked since it seemed blatantly wrong to me, no fork ir I have no local variable, no fork or anything. An object goes it, I unbundle, take the array, multiply by a scalar constant (for example), and rebundle, et voilà , 20 MB used that I will never get back. The workaround I mentionned is indeed the use of the vi http://zone.ni.com/reference/en-XX/help/371361B-01/glang/request_dealloc/' target="_blank">request deallocation which just seems wrong to me for such simple task in an environment that handles memory automatically. Quote Link to comment
Cat Posted May 7, 2009 Report Share Posted May 7, 2009 QUOTE (Ernest Galbrun @ May 6 2009, 08:03 AM) First of all, sorry for my long silence, I have broken my clavicle last sunday and they wouldn't tell me their wifi access code in the hospital. Sorry to hear about your injury. QUOTE I have no local variable, no fork or anything. An object goes it, I unbundle, take the array, multiply by a scalar constant (for example), and rebundle, et voilà , 20 MB used that I will never get back. Isn't this exactly what the In Place Element Structure is for? Or are you using it and it's still creating a copy where it shouldn't be? As a side note, I just "discovered" this structure myself awhile ago (yes, I'm a little slow) and am going thru old code inserting it where possible. I do a lot of manipulations on large data sets and I have been able to see reductions in memory use. Quote Link to comment
Ernest Galbrun Posted May 7, 2009 Author Report Share Posted May 7, 2009 QUOTE (Cat @ May 6 2009, 02:32 PM) Isn't this exactly what the In Place Element Structure is for? Or are you using it and it's still creating a copy where it shouldn't be? Is it ? If I properly understood what was told by Aristos, accessing members of a class necessarily duplicates them in memory (since there is an unbundle/bundle sequence) unless I use the Place Element Structure ? So that would solve the problem I had in the first place, since the sub-vis would then only necessitate a little bit of memory. This is the fix I was looking for, since what I made didn't prevent data to be copied, although there was no need to duplicate the large datasets. Also, this explains why I only saw this using LVClass, since I usually don't encapsulate large datasets in clusters. Concernig the other issue, what I understand is that Labview never deallocate memory unless I ask it to ? Quote Link to comment
ShaunR Posted May 7, 2009 Report Share Posted May 7, 2009 QUOTE (Aristos Queue @ May 5 2009, 12:06 AM) When it needs a copy, it makes a copy. When it does not it does not. An easy example -- if you unbundle data from one object and bundle it into another object, clearly a copy is made along the way. If you unbundle using the Inplace Element Structure, modify the value and then put the value right back into the object using the bundle node on the other side of the structure, no copy is made. Thats more like it does unless you tell it not too. But I can see where you are coming from. I was more talking about if I called method A and passed that data to method B and then on to C. Do I now have 3 copies of that data just because I invoked those methods (and labview has loaded but not released the VI's)?. Or is it just pointer arithmetic (as it would be in other languages ) and there is only 1 data structure and only a pointer is copied? QUOTE he workaround I mentionned is indeed the use of the vi request deallocation which just seems wrong to me for such simple task in an environment that handles memory automatically. This is one of the aspects I really don't like about the "new" labview (far more I do like though). One of the reasons Labview was much faster in developing applications was because (unlike other languages) you didn't have to worry about memory management. As such, you could get on and code for function and didn't necessarily need an in-depth knowledge of how Labview operated under the hood. There used to be no such thing as a memory leak in Labview applications! Now you have to really make sure you close all references and are aware of when references are automatically created (like in queues, notifiers etc). It's good news for C++ converts because they like that sort of nitty gritty. But for new recruits and programming lamen (which was really where Labview made its ground) the learning curve is getting steeper and development times are getting longer. Quote Link to comment
Yair Posted May 8, 2009 Report Share Posted May 8, 2009 QUOTE (ShaunR @ May 6 2009, 10:51 PM) Now you have to really make sure you close all references and are aware of when references are automatically created (like in queues, notifiers etc). References for queues and notifiers are NOT created automatically. You have to explicitly request them. Even then, LV will clean them up automatically if the queue goes out of scope. LV actually got better in recent versions in dealing with references which are created automatically (like control references), so that you don't have to close them. In any case, no one is forcing you to use these (or even a new version of LV). You can go back to an old version, but I still don't see why you say that you have to worry about memory, etc. in the newer versions. It's true that the environment is bigger and heavier, but you still only have to worry about optimizations if you're doing something which challenges the hardware. As Stephen said, LV tries not to make a copy when it doesn't have to. I suggest that Ernest upload actual code we can play with to see the issue he's having ourselves. Quote Link to comment
Grampa_of_Oliva_n_Eden Posted May 8, 2009 Report Share Posted May 8, 2009 QUOTE (ShaunR @ May 6 2009, 03:51 PM) ...This is one of the aspects I really don't like about the "new" labview (far more I do like though). One of the reasons Labview was much faster in developing applications was because (unlike other languages) you didn't have to worry about memory management. As such, you could get on and code for function and didn't necessarily need an in-depth knowledge of how Labview operated under the hood. There used to be no such thing as a memory leak in Labview applications! Now you have to really make sure you close all references and are aware of when references are automatically created (like in queues, notifiers etc). It's good news for C++ converts because they like that sort of nitty gritty. But for new recruits and programming lamen (which was really where Labview made its ground) the learning curve is getting steeper and development times are getting longer. Aristos (and his group) has done a great job of heading off issue with bad performance arising from using LVOOP. The issue Ernest is discovering is not unique to LVOOP is also present when using clusters. There was an in dpeth discusion that was started by Shane on the Dark-Side that can be found here. What LVOOP does is make it easier to get yourself into these cluster related situations. BUT at the same time as LVOOP made the streets (or there-abouts) NI released the inplace operations to let us "reach under the hood" when we have to. I like the "NEW LabVIEW". If I could only learn it as fast as they release it.... Take care, Ben Quote Link to comment
ShaunR Posted May 10, 2009 Report Share Posted May 10, 2009 QUOTE (Yair @ May 7 2009, 05:52 PM) References for queues and notifiers are NOT created automatically. You have to explicitly request them. Even then, LV will clean them up automatically if the queue goes out of scope. LV actually got better in recent versions in dealing with references which are created automatically (like control references), so that you don't have to close them. Lets hope it goes out of scope before you run out of memory then. QUOTE (NI Help) If you use the Obtain Queue function to return a reference to a named queue inside a loop, LabVIEW creates a new reference to the named queue each time the loop iterates. If you use Obtain Queue in a tight loop, LabVIEW slowly increases how much memory it uses because each new reference uses an additional four bytes. These bytes are released automatically when the VI stops running. However, in a long-running application it may appear as if LabVIEW is leaking memory since the memory usage keeps increasing. To prevent this unintended memory allocation, use the Release Queue function in the loop to release the queue reference for each iteration. ----------------------- QUOTE (Yair @ May 7 2009, 05:52 PM) In any case, no one is forcing you to use these (or even a new version of LV). You can go back to an old version, but I still don't see why you say that you have to worry about memory, etc. in the newer versions. Tetchy Quote Link to comment
Yair Posted May 10, 2009 Report Share Posted May 10, 2009 Well, calling Obtain Queue in a loop IS explicitly opening a reference. It's usually kind of pointless too, unless you want N references, and if you have an application where N*4 bytes is large enough to consume all memory then you probably want to rethink your archicture. QUOTE (ShaunR @ May 9 2009, 03:08 PM) Lets hope it goes out of scope before you run out of memory then. No need to hope if you know the rule - a queue is destroyed automatically if all the hierarchies where a reference to it was obtained go idle or out of memory. Relying on that is bad design, though. You should have a release for each obtain. QUOTE Tetchy I am NOT! Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.