Je me suis enseigné Excel VBA au cours des deux dernières années, et j’ai l’idée qu’il est parfois approprié de disposer des variables à la fin d’un segment de code. Par exemple, je l'ai vu faire dans ce bit adapté de code de Ron de Bruin pour le transfert d'Excel en HTML :
Function SaveContentToHTML (Rng as Range)
Dim FileForHTMLStorage As Object
Dim TextStreamOfHTML As Object
Dim TemporaryFileLocation As String
Dim TemporaryWorkbook As Workbook
...
TemporaryWorkbook.Close savechanges:=False
Kill TemporaryFileLocation
Set TextStreamOfHTML = Nothing
Set FileForHTMLStorage = Nothing
Set TemporaryWorkbook = Nothing
End Function
J'ai fait quelques recherches à ce sujet et ai trouvé très peu au-delà de la façon de le faire, et dans un post de forum affirmation qu'aucune variable locale ne doit être effacée , puisqu'elles cessent d'exister à End Sub
. D'après le code ci-dessus, je suppose que ce n'est peut-être pas vrai à End Function
, ou dans d'autres circonstances que je n'ai pas rencontrées.
Donc ma question se résume à ceci:
Et si ce n’est pas quelqu'un qui est ici, veuillez expliquer ...
VB6/VBA utilise une approche déterministe d’objets déstabilisants. Chaque objet stocke le nombre de références à lui-même. Lorsque le nombre atteint zéro, l'objet est détruit.
Il est garanti que les variables d’objet sont nettoyées (définies sur Nothing
) quand elles sortent de la portée, cela décrémente les compteurs de référence dans leurs objets respectifs. Aucune action manuelle requise.
Il n'y a que deux cas où vous souhaitez un nettoyage explicite:
Lorsque vous souhaitez qu'un objet soit détruit avant que sa variable ne devienne hors de sa portée (par exemple, l'exécution de votre procédure prendra beaucoup de temps et l'objet contient une ressource. Vous souhaitez donc détruire l'objet le plus tôt possible pour libérer le contenu. Ressource).
Lorsque vous avez une référence circulaire entre deux objets ou plus.
Si objectA
stocke une référence à objectB
et que objectB
enregistre une référence à objectA
, les deux objets ne seront jamais détruits à moins que vous ne bloquiez la chaîne de manière explicite. réglage objectA.ReferenceToB = Nothing
ou objectB.ReferenceToA = Nothing
.
L'extrait de code que vous montrez est incorrect. Aucun nettoyage manuel n'est requis. Il est même dangereux de faire un nettoyage manuel, car cela vous donne un faux sens d’un code plus correct .
Si vous avez une variable au niveau classe, elle sera nettoyée/détruite lors de la destruction de l'instance de classe. Vous pouvez le détruire plus tôt si vous voulez (voir item 1.
).
Si vous avez une variable au niveau du module, elle sera nettoyée/détruite à la fin du programme (ou, dans le cas de VBA, à la réinitialisation du projet VBA). Vous pouvez le détruire plus tôt si vous voulez (voir item 1.
).
Le niveau d'accès d'une variable (public ou privé) n'affecte pas sa durée de vie.
VBA utilise un ramasse-miettes implémenté par comptage de références .
Il peut y avoir plusieurs références à un objet donné (par exemple, Dim aw = ActiveWorkbook
crée une nouvelle référence dans Active Workbook), de sorte que le ramasse-miettes nettoie un objet uniquement s’il est clair qu’il n’existe aucune autre référence. La définition de la valeur Nothing est un moyen explicite de décrémenter le nombre de références. Le compte est implicitement décrémenté lorsque vous quittez la portée.
Strictement parlant, dans les versions modernes d'Excel (2010+), définir sur Aucune n'est pas nécessaire, mais il existait des problèmes avec les versions antérieures d'Excel (pour lesquelles la solution de contournement devait être explicitement définie).
J'ai au moins une situation dans laquelle les données ne sont pas automatiquement nettoyées, ce qui pourrait éventuellement entraîner des erreurs "Mémoire insuffisante". Dans un UserForm j'avais:
Public mainPicture As StdPicture
...
mainPicture = LoadPicture(PAGE_FILE)
Quand UserForm a été détruit (après Unload Me
) la mémoire allouée pour les données chargées dans mainPicture
n'était pas désaffectée. Je devais ajouter un explicite
mainPicture = Nothing
dans l'événement de terminaison.