2010-11-09 10 views
13

Je suis un programmeur C++ entrant dans le monde de Java. Et je ne peux pas me débarrasser du mauvais sentiment d'avoir à laisser le garbage collector Java faire mon nettoyage.Garbage collection sur une variable locale

Comment, par exemple, ce code va-t-il se comporter en Java? L'objet de variable locale sera-t-il supprimé si myFunction() se termine? Dois-je définir l'objet sur null avant de quitter, ou sera-t-il hors de portée et sera supprimé par le GC? Ou, au pire, va-t-il fuir comme en C++?

Répondre

23

Il sera recueilli à un moment donné après qu'il n'est plus utilisé. Je crois que dans les implémentations actuelles de Java, il persistera jusqu'à la fin de la méthode, alors que le garbage collector dans .NET est plus agressif. (Je ne sais pas s'il y a des garanties même en Java.) Normalement, vous ne voulez que la variable locale à persister au-delà de sa dernière lecture possible lorsque vous déboguez.)

Mais non, vous ne faites pas t besoin de définir la variable sur null, ce qui nuirait à la lisibilité.

Il est peu probable que l'objet soit collecté immédiatement après la fermeture de la méthode; ça dépend du moment où le GC fonctionne ... et bien sûr, si quelque chose d'autre contient une référence à l'objet, il peut ne pas être éligible pour la collecte des ordures de toute façon. Ne pas oublier que la valeur de la variable est juste une référence, pas l'objet lui-même. (Cela peut prendre un certain temps pour s'habituer à C++.)

+0

Dans les implémentations précédentes, il ne persisterait pas réellement jusqu'à la fin de la méthode? Ce serait un peu étrange ... –

+2

@Erick: J'essayais plus d'éviter la garantie que les implémentations * futures * garderaient la variable locale comme une "racine". Le .NET CLR ne le fait certainement pas, et en effet un objet peut être collecté * alors qu'une méthode d'instance est encore en train de l'exécuter "dans" le * tant que le GC sait que rien ne référencera aucun de ses champs. –

+0

@Erick si 'doSomething()' n'utilise aucun autre champ ou méthode de l'objet, ou que le code peut être JITed de sorte que tous les champs soient placés dans des registres et toutes les méthodes inline, alors l'objet peut être collecté avant doSomething() 'se termine, et encore moins' myFunction() '. Le seul critère est de savoir si la signification du code change. –

1

Il va sortir du cadre. En Java, lorsque personne ne pointe plus sur un objet, il sera collecté par le garbage ou au moins il sera disponible pour le garbage collection. Pas besoin de le mettre à null ici. Parfois, la définition d'une référence d'objet à null est nécessaire si votre objet va vivre dans votre App, mais une référence qu'il détient doit être collectée. Dans ce cas, vous choisissez de libérer la référence.

+2

(le -1 est pour la partie scope La portée variable et le cycle de vie de l'objet ne sont pas du tout liés en Java La seconde partie est moins incorrecte, bien que le critère soit l'accessibilité plutôt que le manque de références autre, mais aucun n'est accessible à partir d'un autre objet, alors ils seront collectés même si quelqu'un leur montre) –

+0

Intéressant merci –

2

j'ai rencontré ce code:

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
somethingRunOutOfMemory(); 

somethingRunOutOfMemory() parce myTooBigList n'étaient pas GCable, malgré pas une portée plus.

Comme dans C, les variables locales sont situées dans la pile à côté des trames. Le pointeur de pile réserve autant d'espace que nécessaire pour les variables locales dans la portée. La variable locale d'un bloc devient GCable lorsque la pile est réutilisée. En dehors de la portée, le pointeur est reculé dès que requis par les nouvelles variables locales.

Ils sont GCable après:

try { } catch : after exit by catch because catch reuses stack 
for { } : after exit loop condition because evaluation reuses stack 
while { }: after exit loop condition because evaluation reuses stack 
{ } followed by any local declaration that reuses stack 

Ils ne sont pas GCable après:

try { } finally 
try { } catch : after nothing caught 
for { } : after break 
while { } : after break 
do { } while : after loop condition 
if { } 
{ } not followed by a local declaration 

Si je veux un local pour être GCable j'écris:

{ 
    final List myTooBigList = new ArrayList(); 
    ... overfill the list 
} 
Object fake = null; 
somethingDoesntRunOutOfMemory(); 

Affectation de faux déplace le pointeur de la pile et rend myTooBigList GCable. La surprise est que (au moins dans le jvm que je suis en train de tester) nous devons explicitement réutiliser la pile.On s'attendrait plutôt à ce que les variables locales soient GCables dès la fin du bloc, mais je suppose que c'est un compromis avec les performances. Cela compliquerait beaucoup le bytecode. REMARQUE: pour tester si une variable est GCable, j'exécute GC puis compare un WeakReference (ma variable) à null.

final WeakReference gctest; 
{ 
    final List myTooBigList = new ArrayList(); 
    gctest = new WeakReference(myTooBigList); 
    ... overfill the list 
} 
Object fake = null; 
System.gc(); 
assert gctest.get() == null;