Comptage de référence VBA-destruction D'objets

Dernièrement, je me suis heurté à une question qui m'a fait pounder; cela m'a occupé et je n'ai pas pu trouver une explication transparente sur le net.
Il est lié à la destruction D'objets Excel (que j'utilise tout le temps et jamais vraiment interrogé auparavant).

Contexte menant à ma question:
Avec les objets réguliers, vous pouvez instancier un objet en utilisant les mots clés SET et NEW. Par exemple:

Set classInstance = New className

Chaque fois que nous instancions de cette façon, l'objet est créé dans la mémoire de tas et le compteur de référence est augmenté de 1.
Dans le cas où je n'ajoute pas plus de références, l'instruction suivante ramènerait le nombre de références à zéro:

Set classInstance = Nothing 

Lorsque le nombre de références passe à 0, l'objet est détruit et effacé de la mémoire et le" classInstance " pointe vers .

Ce que j'ai lu:
Lorsque nous utilisons la fonction" CREATEOBJECT", elle renvoie une référence à un objet COM.

Set oApp = CreateObject("Excel.Application")

Même si nous pourrions dire:

Set oApp = nothing 

Le nombre de références des objets ira à 0, et oApp ne pointera plus vers l'objet.

Mes questions:
1) Pourquoi est - ce que ce type d'objet nécessite d'appeler la méthode .Quitter avant que l'objet ne soit réellement retiré de la mémoire?
Il en va de même lors de l'ajout d'une référence à un objet classeur (classeurs.ajouter ou classeur.ouvert), qui exige de la .méthode close. Pourquoi ces objets ne peuvent-ils pas être automatiquement détruits lors de l'apport de la référence décompte à zéro?
Ce qui est le cas quand on dit par exemple:

set oRange = nothing 

2) et est-il nécessaire de dire:

oApp.Quit
set oApp = nothing 

Puisque L'objet Application est déjà effacé de la mémoire lors de l'application .Quitter, il n'y a plus d'objet à libérer.
La seule raison pour laquelle je pourrais trouver, pourquoi oApp serait mis à rien après Quit, serait parce qu'il pourrait pointer vers un emplacement de mémoire inutilisé (sur le tas) et pourrait conduire à la confusion plus tard si cette mémoire serait réattribuée (bien que dans VBA je trouve cela difficile à imaginer). Je me demandais si cette conclusion était correcte et je voudrais recevoir une confirmation de quelqu'un qui connaît la réponse.
S'il te plaît, dis-moi si je vois ça à tort.

3) ce qu'ils appellent dans VBA " une référence à un objet "(comme oApp dans le code ci-dessus), je les vois comme des variables de pointeur dans C. Serait-il prudent d'utiliser cette Déclaration ou encore, est-ce que je vois cela à tort?

, n'est Généralement pas difficile à appliquer .Arrêter de fumer et mis à rien, mais il serait bon de recevoir des informations précises sur le sujet. Alors que je sais pour 100% pour cent pourquoi je le fais.

22
demandé sur Community 2012-07-09 16:38:40

2 réponses

Bonne Question:)

Excel contrôle la création de ses objets. De même, il contrôle également leur destruction.

Le paramètre oApp = Nothing détruit simplement la référence de l'objet. Il ne supprime pas l'Application. Pour détruire un objet Excel, vous devez utiliser sa méthode .Quit.

Chaque fois que vous le faites, Set x = Nothing, la référence(pointeur) nommée x à son objet pertinent est supprimée. Cela ne signifie pas que l'objet lui-même sera supprimé de la mémoire. Si l'objet sera supprimé de la mémoire ou non, dépend de divers facteurs.

  1. indique s'il y a plus de références pointant vers le même objet. S'il y en a, l'objet ne sera pas supprimé. Le nombre de référence doit être nul.
  2. l'implémentation interne du destructeur de cet objet.

La méthode .Quit est définie pour supprimer gracieusement tous les objets mémoire alloués par excel et se fermer.

C'est similaire à appeler Close sur un formulaire dans VB6. Prenons, par exemple, un forme en vb6.

Dim f As Form
Set f = Form1
f.Show

'
'~~> Rest of the code
'

Set f = Nothing

Cela détruira-t-il la forme? :)

SUIVI

Que diriez-vous de la question 2? Merci-Kim Gysen 14 Il y a quelques minutes

entrez la description de l'image ici

Ce n'est peut-être pas exactement comme indiqué ici, et les optimisations du compilateur peuvent faire en sorte que les choses se comportent différemment... mais c'est le concept de base qui est à l'œuvre.

11
répondu Siddharth Rout 2012-07-09 14:07:00

La Partie 2 de votre question est assez intéressante, et cela vaut bien une réponse étendue.

Cela va couvrir trois points clés:

  • objets et variables d'objet;
  • pièges lors du rejet d'objets;
  • ...Et un changement important dans la référence-Compter l'objet D'Application dans Excel 2013.
Mais, si vous voulez une réponse courte, c'est: "tous les objets ne sont pas égaux".

Maintenant, lisez la suite...

Certains objets sont créés dans l'espace mémoire 'propre' de votre session Excel, et leur allocation de mémoire est contrôlée par votre session; Certains objets ont des composants persistants qui existent après le rejet de la variable objet; et d'autres non: {[0]}

Dans ces deux cas, la mémoire est allouée, les variables d'objet (et leur vTable de pointeurs vers les méthodes et les propriétés) sont instanciées, et elles sont à vous de commander jusqu'à ce que vous les rejettiez:
{[1]}

Et, en cas de licenciement, aucune trace d'eux reste.

Mais cet objet est persistant: {[2]} ...Vous avez créé un nouvel objet classeur et, si vous ignorez la variable objet avec Set oWbk = Nothing, vous verrez que le nouvel objet classeur existe toujours en tant que présence visible dans l'interface utilisateur.

Ce que vous avez réellement créé était un classeur objet - une fenêtre de classeur avec une feuille de calcul active et l'interface utilisateur complète qui va avec cela-et un classeur variable objet - COM d'un programmeur interface, une table de méthodes et de propriétés pour l'objet classeur - que vous pouvez manipuler dans le code en utilisant l'entité nommée 'oWbk'.

Le rejet de la variable d'objet oWbk supprime ce framework, mais le classeur lui-même existera toujours: vous avez créé un objet classeur, et c'est à vous de le conserver.

L'objet est plus que sa variable objet et rejeter la variable ne détruit pas l'objet: il rejette simplement une interface, un cadre de méthodes et les propriétés que vous pouvez utiliser pour manipuler l'objet dans le code.

La fermeture du classeur, avec ou sans enregistrer un fichier, devrait automatiquement rejeter la variable objet et effacer la mémoire allouée pour cette interface de propriétés, méthodes et attributs: {[3]} ...C'est-à-dire que vous vous attendez à ce que ces deux commandes appellent Set oWbk= Nothing - en particulier la commande oWbk.Close - mais si vous essayez l'une d'elles sans rejeter explicitement oWbk, vous constaterez que oWbk existe toujours en tant que vide husk, et tous les appels et demandes d'informations à ce sujet (try> Debug.Print> TypeName(oWbk) ) retournera 'erreur D'automatisation' messages.

Certains des commentaires de la réponse précédente mentionnent l'objet UserForm qui, contrairement au dictionnaire et à L'objet Shell, est un objet avec une interface utilisateur visible. Mais cette interface utilisateur n'est pas persistant nouvel objet dans l'interface utilisateur d'Excel comme un Classeur ou une feuille de calcul.

Heureusement pour vous, l'objet que vous avez créé appartient à votre Excel session, et vous pouvez instancier une variable d'objet à nouveau, pour obtenir le même cadre de méthodes et de propriétés, et prendre le contrôle de l'objet à nouveau: {[4]} ...En supposant, bien sûr, que vous avez un moyen d'être sûr que vous avez identifié le bon objet classeur: mais ce n'est pas votre question du tout.

Où va cette réponse est: les objets qui ne sont pas créés dans la mémoire 'propre' de votre session Excel. {[5]} Cette instruction va créer un objet Excel qui, comme le nouveau classeur, a une Interface utilisateur (bien que vous ayez besoin de définir la propriété .Visible True pour la voir) et une présence persistante en mémoire: encore une fois, l'objet est plus que sa variable d'objet, et la dismissing de la variable ne détruit pas l'objet.

Contrairement au nouveau classeur, ce n'est pas tout à fait à vous de commander: c'est une session Excel à part entière, elle alloue sa propre mémoire - l'empreinte d'oApp dans la mémoire de votre session actuelle est juste le pointeur et le nom: l'interface (vTable, iDispatch, et toutes ces méthodes nommées avec des pointeurs vers les structures qui implémentent l'acte arcane de manipuler une session Excel dans VBA) existe dans le bloc de mémoire alloué par cette nouvelle session Excel.

Voici ce qui se passe dans Office 2010, et les anciennes versions D'Excel:

Rejeter la variable d'objet avec Set oApp = Nothing laisse cette session en cours d'exécution, et je vous suggère fortement de rendre la session visible afin que vous puissiez la fermer manuellement!

Fermer cette session Excel manuellement, sans rejeter explicitement la variable d'objet oApp, définitivement laissera oApp dans l'état 'empty husk', et un spectre sombre et sans tête pleurant 'L'objet Automation s'est déconnecté de ses clients!' dans les coins sombres de votre base de code.

Mais, dans Office 2013 et les versions ultérieures, Set oApp = Nothing effectue exactement le comptage de référence que vous attendez et la session se ferme. Essayer: {[6]} Il ne sera pas fermez {[20] } si une autre variable d'objet a une référence-et ce n'est pas la seule entité qui incrémente le compteur de référence: l'activité de l'utilisateur dans l'interface graphique (essayez de créer un nouveau classeur et de le modifier) maintient la session en cours d'exécution.

Pour votre propre amusement, voyez si oApp.Quit rejette réellement oApp et le définit sur Nothing.

Bien sûr, {[24] } va définitivement fermer la session...

...Ou sera-ce? Si il se passe quelque chose dans cette session - un long calcul, ou un message d'erreur' modal ' que vous devez voir et cliquer avant que l'objet Application ne réponde à n'importe quelle autre entrée, de l'interface utilisateur ou de votre VBA - alors oApp.Quit ne fermera pas la session.

N'y allons pas. Toutes choses étant égales par ailleurs, {[24] } fermera définitivement la session en 2010 et les versions antérieures D'Excel.

Mais dans Office 2013, l'appel de 'Quit' à partir de la dernière variable d'objet Cache simplement l'interface utilisateur: la variable d'objet répond toujours à votre code - les méthodes et les propriétés qui ne nécessitent pas de classeur actif sont toujours accessibles via oApp-et une instance distincte D'Excel.exe est clairement visible dans l'onglet Processus du gestionnaire des Tâches.

De même, quitter la nouvelle session en cliquant sur le bouton' Fermer ' dans l'interface utilisateur ferme les fenêtres de la session mais, s'il y a une variable d'objet avec une référence à cet objet d'application dans votre code, il est toujours là, en mémoire, et 'oApp' peut toujours obtenir les propriétés et les méthodes.

Ainsi, le compteur de référence fonctionne dans les deux sens dans les versions actuelles D'Excel: l'objet existe jusqu'à ce que le nombre de références diminue à zéro, et la dernière variable d'objet restante serapas laissée 'déconnectée' par une commande quit ou une action UI.

Néanmoins, votre session ne 'possède' pas ce nouvel objet d'application: si vous avez rejeté la dernière variable d'objet et la définissez sur Nothing, et qu'il y a autre chose qui maintient la session neww en vie-user activité, ou un processus interne-il n'y a rien comme L'Application.Classeurs() ou Worksheets () collection pour identifier d'autres sessions Excel et instancier une variable objet pointant vers une instance spécifique D'un Excel.Objet d'Application.

Il existe des moyens d'obtenir une session spécifique en utilisant des appels D'API, mais ils ne sont pas aussi fiables que vous le souhaitez.

...donc, dans l'ensemble, il y a beaucoup dans cette "partie 2".

1
répondu Nigel Heffernan 2017-08-30 20:00:43