2008-10-10 8 views
18

Est-il possible de forcer par programme une récupération complète de la récupération de place dans ActionScript 3.0? Disons que j'ai créé un tas d'objets Display avec eventListeners et que certains des DO ont été supprimés, que certains eventListeners ont été déclenchés et supprimés, etc ... Y a-t-il un moyen de forcer le garbage collection à s'exécuter? collecter tout ce qui est disponible pour être collecté?Force Garbage Collection dans AS3?

Répondre

25

Oui, c'est possible, mais c'est généralement une mauvaise idée. Le GC devrait avoir une meilleure idée de quand est le bon moment pour exécuter que vous devriez, et sauf pour un cas très spécifique, comme vous avez juste utilisé 500 Mo de mémoire et vous devez le récupérer dès que possible, vous ne devriez pas appeler le GC toi même.

Dans Flash 10, il existe une méthode System.gc() que vous pouvez appeler (mais ne le faites pas, voir ci-dessus) - gardez à l'esprit System.gc() ne fonctionne que dans la version de débogage de Flash player 10+.

Dans Flash 9, il existe un moyen non pris en charge pour le forcer via une commande LocalConnection impaire, mais il peut ne pas fonctionner dans toutes les versions. Voir this post par Grant Skinner.

+7

C'est une bonne réponse - mais il manque un point très important. Cela ne fonctionne que dans les débogueurs! System.gc() - Pour la version de débogage de Flash Player et les applications AIR uniquement. Dans une application AIR, la méthode System.gc() est activée uniquement dans le contenu exécuté dans AIR Debug Launcher (ADL) ou, dans une application installée, dans le contenu du sandbox de sécurité de l'application. [http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/system/System.html#gc()] –

+1

Je ne le savais pas. – Glycerine

+5

Dans Flash 11, il existe un 'System.pauseForGCIfCollectionImminent() 'méthode que vous pouvez appeler. Il faut un argument pour que vous puissiez donner au GC une idée de l'imminence d'une collection pour que la pause se produise. Pour plus de détails/liens, voir ma réponse ci-dessous. – pnkfelix

8

Pour toutes les versions actuellement publiées, System.gc() ne fonctionne que dans la version de débogage du lecteur Flash et ADL (l'environnement de débogage pour les applications AIR). Flash Player 10 beta fonctionne actuellement dans toutes les saveurs.

Je suis d'accord avec Davr, c'est une mauvaise idée à faire. Le runtime aura généralement une meilleure idée que vous. De plus, les détails sur le fonctionnement du garbage collector sont des détails d'implémentation susceptibles d'être modifiés entre les versions de Flash Player. Donc ce qui fonctionne bien aujourd'hui n'a aucune garantie de bien fonctionner dans le futur.

+0

Il existe un cas spécifique, j'ai une classe DataCache, la façon dont cela fonctionne est de garder l'objet de résultat qui envoie des événements mis à jour lors de l'actualisation/réception de données. La façon dont le cache est nettoyé est que je nettoie juste tous les résultats de celui-ci et j'envoie l'événement qui amène tous les écouteurs restants à re-demander leurs données. Si je ne peux pas forcer tous les écouteurs qui attendent encore que GC soit nettoyé immédiatement avant d'envoyer l'événement d'actualisation, ces écouteurs vont demander à nouveau des données. – FredV

3

Comme d'autres l'ont dit: n'essayez pas de GC manuellement, il y a des hacks mais ce n'est pas sûr.

Vous devriez essayer en recyclant objets lorsque vous le pouvez - vous économiserez beaucoup de mémoire.

Cela peut être appliqué par exemple à BitmapDatas (effacer et réutiliser), particules (supprimer de l'affichage et réutiliser).

3

J'ai un commentaire sur ceux qui disent que vous ne devriez jamais faire GC manuellement. Je suis habitué à la gestion manuelle de la mémoire en C++ et je préfère sharedptr sur GC, mais de toute façon.

Il y a un cas spécifique où je ne peux pas trouver une autre solution que faire un GC. Veuillez considérer: J'ai une classe DataCache, la façon dont elle fonctionne est de garder les objets de résultat pour certains appels de méthode qui envoient des événements mis à jour lors de l'actualisation/réception de données. La façon dont le cache est rafraîchi est que je nettoie tous les résultats et envoie l'événement qui oblige les écouteurs restants à re-demander leurs données et les écouteurs hors de portée ne doivent pas demander qui nettoie les résultats non nécessaires. Mais apparemment, si je ne peux pas forcer tous les auditeurs qui attendent encore que le GC soit nettoyé immédiatement avant d'envoyer l'événement «demandez à nouveau des données», ces auditeurs qui attendent vont demander à nouveau des données inutilement. Donc, comme je ne peux pas enleverEventListener parce que AS3 n'a pas de destructeur, je ne vois pas d'autre solution facile que de forcer un GC à s'assurer qu'il n'y a plus d'écouteurs qui se balancent.

(Edit) En plus de cela, je ne peux pas utiliser removeEventListener quand même pour la liaison qui ont été installés dans MXML, par exemple (en utilisant ma classe DataCacher personnalisée qui gère remoteobj)

<mx:DataGrid id="mygrid" dataProvider="{DataCacher.instance().result('method').data}" ... /> 

Lorsque la fenêtre pop-up contenant ce DataGrid est fermé, vous vous attendriez à ce que les liaisons soient détruites. Apparemment, ils vivent encore et encore. Hmm, ne devrait pas fléchir détruire toutes les liaisons (signifiant eventlisteners) d'un objet quand il est marqué pour GC parce que la dernière référence est supprimée. Cela permettrait de résoudre le problème pour moi.

Au moins c'est pourquoi je pense, je suis encore un débutant en Flex donc toutes les pensées seraient appréciées.

0

Si vous devez le faire, appeler le collecteur gargabe pourrait vous être utile ... alors, vous devez faire attention quand et comment vous le faites, mais il ne fait aucun doute qu'il y a des moments où cela est nécessaire. Par exemple, si vous avez une application modulaire, lorsque vous passez d'une vue à l'autre, tous les objets supprimés peuvent représenter une grande quantité de mémoire disponible le plus rapidement possible. Il vous suffit de avoir le contrôle des variables et des références que vous éliminez.

0

Le recyclage n'aide pas vraiment. J'ai utilisé un chargeur qui a chargé à plusieurs reprises le même jpg toutes les 500ms. le gestionnaire de tâches signalait toujours une augmentation continue de la mémoire.

solution éprouvée ici.

http://simplistika.com/as3-garbage-collection/

3
try { 
    new LocalConnection().connect('foo'); 
    new LocalConnection().connect('foo'); 
} catch (e:*){ 
    trace("Forcing Garbage Collection :"+e.toString()); 
} 
+0

Pouvez-vous expliquer quel est le lien avec le GC et pourquoi cela le forcerait? – duTr

14

Il y a une nouvelle API pour dire au GC qu'il pourrait être un « relativement bon moment » pour recueillir.

Voir l'API Adobe docs pour System.pauseForGCIfCollectionImminent

Et aussi cette Adobe blog post de peu de temps après la méthode a été introduite dans la version Player 11

La méthode prend un argument "imminence"; Fondamentalement, vous alimentez un nombre faible (près de 0.0) si vous voulez vraiment que le collecteur fonctionne, même s'il n'y a pas eu beaucoup d'activité (actuellement mesurée par octets alloués) depuis la dernière collecte, et que vous en alimentez un grand nombre (près de 1.0) si vous voulez seulement que la pause de la collection se produise si nous étions déjà près du point où une collection arriverait de toute façon.

La motivation ici est pour des situations dans par ex. des jeux où vous voulez déplacer le point où les GC se produisent d'une petite quantité, par ex. faites le GC pendant un changement de niveau dans le jeu, plutôt que deux secondes après que le joueur a commencé à explorer le niveau.

Un détail très important: Cette nouvelle API est supportée par les versions d'exécution et de débogage Flash. Cela le rend supérieur à l'appel System.gc().