Jump to content

Fermeture Références


Recommended Posts

Bonjour je suis nouveau sur ce site,
 
Je reprenais le code d'un collègue qui me met le doute sur les fermetures de références. C'était déjà pas toujours très clair pour moi mais la c'est la grosse interrogation. 
 
Sur l'image jointe :
- Sur la partie supérieure les références des clusters, et des clusters formaté en slide (strict), sont fermés a la fin du Vi. Cela sert a quelque chose cela? Pour moi c'est inutile.
- Sur la partie inférieure, c'est un appel ActiveX de Solidworks. La j'ai un doute, avant j'aurais fait comme cela, mais maintenant je me demande si c'est vraiment utile de fermer toutes les références qui découlent de la référence ouverte au démarrage (ISldWorks). Juste la fermeture de la référence ouverte au démarrage suffit, non? Cela sert a quelque chose de fermer les références intermédiaires?
 
Merci

Question ActivX.png

Link to comment

pour les refs activeX, oui je pense qu'il faut les fermer.

Pour les refs de controles, je te renvoie à la présentation de Darren Nattinger : https://forums.ni.com/t5/LabVIEW/Which-references-need-to-be-quot-Closed-quot/m-p/3775021#M1063802

Tu peux lire l'entier du fil... mais c'est un peu long

 

Edited by Antoine Chalons
Link to comment

Please note that unless you use a very old LabVIEW version, there is actually no need to put the Close Reference node into a loop. It perfectly will accept an array of refnums too.

As to worrying about if a Close Reference node is necessary or not during a code review, tell the reviewer that there are more important things to worry. 😃

If that are the only things he can complain about, he is either worthless as a code reviewer or your code is prime quality. 😀

For ActiveX (and .Net) refnums it absolutely and positively is important to avoid potentially huge memory hogs (not really memory leaks as LabVIEW still knows about the objects, they just never get disposed until you terminate your application). One of the VI reference close functions marked as questionable also is needed, the other not! ActiveX and .Net objects are refcounted and will often prevent not just themselves to be deallocated but also parent objects, depending if the child object has somehow acquired a reference to the parent for some reason. Any such object wanting to retain access to another object is required to obtain a reference to it which will increase the refcount and only once each reference to an object has been properly closed, will the object actually be released. LabVIEW as simply being another client of the ActiveX or .Net object needs to follow that rule too, so if you don't close the LabVIEW refnum, it won't release the underlying reference to the object and any objects that this object has referenced will also stay in memory.

So rather than erring on the wrong side I prefer to err on the good side and simply put a Close Reference anywhere without even spending a Joule of energy to reason if it is really needed. That little extra muscle exercise in the fingers is not that bad. A Close Reference on a refnum that does not need to be closed is simply a NOP (No Operation) in LabVIEW (well factually it is checking a dynamic attribute of the refnum and skipping any attempt to close the refnum if it doesn't need to but that check is about as expensive as your "Not A Number, Path, Refnum" node).

So from all the marked Close functions the ones being marked OK are indeed needed. From all the others only one can be definitely deleted (the array of control refnums obtained by the Control Reference Constants) . All the ActiveX closes are definitely needed and the refnum returned from the Controls[] property of the Cluster refnum might be maybe not required. But I wouldn't want to go and spend any energy to find out about that so I would leave it in, which would only make one Close being clearly useless (the uppermost).

Edited by Rolf Kalbermatter
  • Haha 1
Link to comment

Merci @Antoine Chalons et @Rolf Kalbermatter pour vos réponses rapide 🙏

J'utilise la version de Labview 2021, et je ne savais pas que l'on pouvait renter un tableau sur un "Close référence". Merci pour l'info 😄!

Je suis très autodidacte sur Labview, avec tout ce qui va avec le bon et le moins bon... J'ai commencé sur la version 5.1 et je dois dire qu'il y a eu quelques évolutions entre la version 5.1 et la version 2021. 

J'ai une autre question sur les ActivesX ou .NET. Doit-on fermer les références que l'on utilise pas mais qui doivent être ouvertes quand même je suppose. Si je suis le conseil de @Rolf Kalbermatter il vaut mieux les fermer dans le doute.

Il existe un moyen pour voir si on ferme bien tout ce qui doit-être fermé, pour éviter les fuite mémoire?

 

Cordialement

Question ActiveX 2.png

Link to comment
25 minutes ago, Francois Aujard said:

J'ai une autre question sur les ActivesX ou .NET. Doit-on fermer les références que l'on utilise pas mais qui doivent être ouvertes quand même je suppose. Si je suis le conseil de @Rolf Kalbermatter il vaut mieux les fermer dans le doute.

Yes, absolutely. Each property(or method) node returning a refnum will increment its object refcount. So if you have two properties "CameraInfo" they may reference the same object but are in fact different references to the same object instance. In fact they use double memory, once for the LabVIEW refnum itself to manage the reference (an int32 pus some extra information including the underlaying .Net or ActiveX reference pointer) and the actual object data space. That object will only go out of memory when ALL the references were closed and that means you have to close the according LabVIEW refnum so it can inform .Net or ActiveX that that reference is not needed anymore.

There are other memory leaks actually in your code. First you assign the instance refnum for the originally opened Camera object to the NET Camera local control then you Open a new reference to a new camera object and assign it to the same local control, losing the original refnum object, so you can never again close it yourself (LabVIEW eventually will when your code hierarchy in which you executed the Constructor goes idle, but that is typically only when you finish your program. Generally using locals (or even worse globals, shudder) to store refnums is a very bad idea. It makes proper life time control of objects rather hard and error prone.

Edited by Rolf Kalbermatter
Link to comment

There are other memory leaks actually in your code. First you assign the instance refnum for the originally opened Camera object to the NET Camera local control then you Open a new reference to a new camera object and assign it to the same local control, losing the original refnum object, so you can never again close it yourself (LabVIEW eventually will when your code hierarchy in which you executed the Constructor goes idle, but that is typically only when you finish your program. Generally using locals (or even worse globals, shudder) to store refnums is a very bad idea. It makes proper life time control of objects rather hard and error prone.

 

En fait il y a deux contrôles différents "Camera" et "ICamera". Ils se ressemblent mais pointent sur 2 variables locales différentes. Les variables locales (tout comme les globales) sont quand même très pratiques, et pour ce genre d'opération cela ne prend quasi rien de mémoire. Sauf erreur de ma part, un référence à un activeX n'est qu'un pointeur? J'évite ce genre de variable lorsque je dois manipuler des gros tableaux de données. A ce moment la je préfères utiliser des FGV.

Ici c'est un code d'essai pour prendre le contrôle d'une caméra GigE mais cela ne marche pas comme je le veux. Que ce soit en .Net ou une Dll. Il y a des class que je ne peux pas avoir, je ne sais pour quelle raison... Il y a aussi des choses que je ne comprend pas bien en regardant les exemple en C# ou C++...  C'est très intéressant, mais le temps passe et si j'y passe plus de temps cela ne sera pas rentable pour l'entreprise (dommage). Je vais commander le module "Vision Acquisition Sofware" pour 575€ cela ne vaux pas le coupe de s'embêter....  

Link to comment

The problem in this specific case is not about memory, although a refnum uses more than just a pointer, but not much more (the underlying object may however use tons of memory!). The problem is rather that it is very easy to lose the overview of which local (or global) is what and where it is initialized and where does it need to be deallocated.

Yes, aside for real UI programming I consider use of locals and globals a real sin!

Link to comment

the underlying object may however use tons of memory! Qu'est ce que vous voulez dire? La mémoire utilisée par l'appel d'une API n'est pas supérieur à la mémoire utilisée par le logiciel propriétaire de l'API? Ce que je veux dire, par exemple : si j'ouvre SolidWorks, ou que j'ouvre Solidworks via Laview par appel d'API. La mémoire utilisée sera la même? Evidement il y aura une partie en plus pour Labview dans le 2eme cas, mais la quantité de mémoire utilisée pour SolidWorks c'est la même non? 

Yes, aside for real UI programming I consider use of locals and globals a real sin! Ah oui carrément ! Vous n'utilisez jamais de variables globale ou local ? Vous faites que des FGV? 

 

Merci pour vos réponses a mes questions 🙂

 

Link to comment
1 hour ago, Francois Aujard said:

the underlying object may however use tons of memory! Qu'est ce que vous voulez dire? La mémoire utilisée par l'appel d'une API n'est pas supérieur à la mémoire utilisée par le logiciel propriétaire de l'API? Ce que je veux dire, par exemple : si j'ouvre SolidWorks, ou que j'ouvre Solidworks via Laview par appel d'API. La mémoire utilisée sera la même? Evidement il y aura une partie en plus pour Labview dans le 2eme cas, mais la quantité de mémoire utilisée pour SolidWorks c'est la même non? 

Lets suppose you create a .Net Image object. That image can potentially use many megabytes of memory. Any reference you obtain for that image will refer to the same image of course so references don't multiply the memory for your image, but LabVIEW will need to create a unique refnum object to hold on to that reference and that uses some memory, a few dozen bytes at most. However every such refnum holds a reference to the object and an object only is marked for garbage collection (for .Net) or self destructed (for ActiveX) once every single reference to it has been closed. So leaving a LabVIEW refnum to such an object open will keep that object in memory until LabVIEW itself terminates the VI hierarchy in which that refnum was created/obtained/opened, as LabVIEW does register every single refnum in respect to the top level VI in whose hierarchy the refnum was created and when that top level VI goes idle (terminates execution), the refnum is closed and the underlying reference is disposed. And to make matters even worse, if such an object somehow obtained a reference to one or more other objects, those objects will remain in memory too until the object holding those references is closed, and that can go over many hierarchy levels like this, so a single lower level object can potentially keep your entire object hierarchy in memory. If and how an object does that is however specific to that object and seldom properly disclosed in the documentation, so diligently closing every single refnum as soon as possible is the best way to make this manageable.

Yes, aside for real UI programming I consider use of locals and globals a real sin! Ah oui carrément ! Vous n'utilisez jamais de variables globale ou local ? Vous faites que des FGV? 

In fact the only globals I allow in my programs nowadays are booleans to control the shutdown of an entire system or "constants" that are initialized once at startup from a configuration file for instance and NEVER after.

The rest is handled with tasks (similar to actors) and data is generally transferred between them through messages (which can happen over queues, notifiers, or even network connections.

Locals are often needed when programming UI components as you may have to update a control or indicator or read it outside of its specific event case, but replacing dataflow with access to locals in pure functional VIs is a sure way to get a harsh remark in any review I would do.

And while I have been a strong supporter of FGVs in the past I do not recommend them anymore. They are better than globals if properly implemented (which means not just a get and set method, which is just as bad as a global, but NEVER EVER any read-modify cycle outside of the FGV.). But they get awkward once you do not just have one single set of data to manage but want to handle an array of such sets, which is quite often. Once you get there you want to have a more database like method to store them, rather than trying to prop them into an FGV.

Edited by Rolf Kalbermatter
Link to comment

Je fermerais toutes les références comme vous me l'avez conseillé. Je vais également surveiller la mémoire du PC lorsque je manipulerais les références ActiveX et .NET. Je ferais tourner mon Vi 1000000 de fois et si la mémoire Windows augmente, c'est que j'ai pas tout bien fermé 😉. Concernant les FGV suis d'accord avec vous. J'utilise aussi les file d'attente, par contre je n'utilise pas les notificateurs. J'utilise les évènements dynamiques qui font pour moi la même chose mais en mieux je trouve.

Merci beaucoup @Rolf Kalbermatter pour toutes ces informations. Merci également pour le temps que vous avez pris pour me répondre.

J'aurais encore plein de questions, mais qui n'auraient rien à voir avec les fermetures de référence. 
 

Edited by Francois Aujard
Link to comment
On 9/2/2022 at 9:42 AM, Francois Aujard said:

Hello @Rolf Kalbermatter,

Just to be sure, that I understand well your previous post. The first case in the attached picture automattillcy close the child reference (CameraInfo ; Parameters and StreamGrabber) or I need to close all childs references before close the parent reference? 

 

Question ActiveX 3.png

Nope! You have to do it like in the lower picture.

And while the order "should" not matter, it's after all the intend of using reference counts to not allow a client to dispose an object before all other clients have closed it too, I try to always first close the sub objects and then the owner of them (just as you did). There are assemblies and especially ActiveX automation servers out there who don't properly do ref counting and may spuriously crash if you don't do it in the right order.

Edited by Rolf Kalbermatter
  • Thanks 1
Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.