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;
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 ... –
@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. –
@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. –