2010-01-20 3 views
1

Je tiens à confirmer que le scénario provoquera une collecte des ordures sur l'objet myObj:Quel objet sera collecté?

Scénario 1

ArrayList arList = new ArrayList(); 
while(someCondition) 
{ 
    myObj = new MyObect(); // a custom object 
    arList.add(myObj); 
} 

Scénario 2

ArrayList arList = new ArrayList(); 
while(someCondition) 
{ 
    myObj = new MyObect(); // a custom object 
    arList.add(myObj); 
    myObj=null; 
} 

Est-ce que la définition explicite d'un objet comme null améliore le comportement de récupération de place ou sera-t-il identique lorsque je réinitialise l'objet en utilisant le nouveau constructeur?

+6

Dans ce cas, il ne semble pas que myObj ait jamais une récupération de place tant qu'arList ne sera plus utilisé. –

+0

hmm .. mais je ne souhaite pas conserver 2 copies de myObj, une dans arList et une dans la variable d'origine. Comment puis-je vider myObj une fois que je l'ai ajouté à arLsit? –

+6

Il n'y a qu'une seule copie de 'myObj', mais il y a deux * références *. En interne, c'est la même chose que d'avoir un objet et deux pointeurs. –

Répondre

7

Vous ne spécifiez pas la portée de myObj et son importance. Si c'est une variable locale, cela n'a certainement pas d'importance. Si la variable d'instance alors que pourrait être une référence à long terme et inutile dans ce cas, la mise à null sera utile.

Update: compte tenu des informations mises à jour que myObj est local à la méthode, il sera d'une valeur nulle pour le mettre à null à la fin de chaque itération de la boucle. Considérez cet exemple:

public void process(String text) { 
    String[] lines = text.split("\n"); 
    List<MyObject> list = new ArrayList<MyObject>(); 
    Object myObj; 
    for (String line : lines) { 
    myObj = new MyObject(line); 
    list.add(myObj); 
    // 1. set myObj = null here 
    } 
    list = null; // 2 
    // 3. do some other stuff 
} 

public class MyObject { 
    private final String line; 

    public MyObject(String line) { 
    this.line = line; 
    } 
} 

maintenant dans cet exemple, disons que à l'étape 3, il a fallu longtemps. Dites 10 minutes. Pendant ces 10 minutes myObj pointe vers la dernière ligne traitée. Ça ne ressemble pas à un problème? Eh bien, ça pourrait l'être. La façon dont les sous-chaînes fonctionnent en Java est qu'elles font référence à la chaîne d'origine. Donc, si vous faites:

String s = ... // 100 megabytes 
String s2 = s.substring(100, 101); 

vous gardez en fait 100 Mo dans la mémoire car s2 fait référence à s.

Ainsi, dans la fonction que j'ai ci-dessus, les références myObj une ligne qui fait référence à l'ensemble du dossier. Changer l'étape 1 à myObj = null; aiderait réellement parce que cette référence empêche l'objet d'être collecté.

Remarque: l'étape 2 est importante ici car si vous n'aviez pas annulé la liste, toutes les références existeraient de toute façon.

Vous avez juste besoin de réfléchir sur la façon dont fonctionnent les références. Un objet ne sera pas collecté alors qu'il existe une référence à celui-ci. Cela signifie effacer les références de longue durée et conserver des variables aussi précises que possible.La bonne solution pour ce qui précède est:

for (String line : lines) { 
    Object myObj = new MyObject(line); 
    ... 
} 

puis myObj est SCOPED dans la boucle dès que la boucle se termine ou commence une autre itération, il est passé hors de portée, ce qui est beaucoup mieux. Parce qu'il est dans un while, myObj est toujours écrasé (la référence)

+0

ajouté portée de myObj. Son local à la méthode –

+0

Merci tas, je suppose que je faisais face à un problème de type similaire –

+0

@Ravi: vous êtes les bienvenus. :) – cletus

6

La définition à null n'aura aucun effet, puisque l'objet est toujours reachable via arList.

En d'autres termes, vos instances MyObect vont vivre au moins aussi longtemps que arList.

EDIT: En fonction de votre commentaire, il semble que myObj a une durée de vie plus longue. Dans ce cas, réglez-le sur null après la fin de votre boucle.

1

Donc, dans le scénario 1, un seul objet (le dernier ajouté dans arList) ne sera pas null.

Il serait mieux si vous déclarez dans la déclaration while:

while(someCondition) 
{ 
    MyObect myObj = new MyObect(); // a custom object 
    arList.add(myObj); 
} 
+0

cela fera-t-il que myObj sera ramassé après la sortie de la boucle? –

+2

@Ravi Non, encore une fois, parce que l'objet a été ajouté à 'arList'. Il sera éligible pour la récupération de place lorsqu'il n'y aura plus de références à 'arList'. – ZoogieZork

+0

Merci, je suppose que j'ai eu ma réponse. –

2

Je pense que c'est la racine de votre incompréhension.

hmm .. mais je ne souhaite pas conserver 2 copies de myObj, une dans arList et une dans la variable d'origine. Comment puis-je vider myObj une fois que je l'ai ajouté à arLsit?

Vous ne "gardez pas deux copies de myObj". Dans vos exemples, il n'y a jamais qu'une seule "copie" de chaque instance de MyObject créée par la boucle. La séquence est:

  1. Vous créez une instance MyObject, attribuant sa référence à myObj.

  2. Vous ajoutez la référence à l'instance à ArrayList à laquelle fait référence arList.

  3. Vous assignez null à la référence en myObj.

Notez que l'ajout de la référence à la liste ne crée PAS une copie de l'occurrence MyObject. Cela signifie simplement que vous avez la référence à deux endroits au lieu de . Et lorsque vous affectez le null vous avez de nouveau la référence en un seul endroit.

L'autre chose à noter est qu'affecter null à quelque chose ne provoquera jamais le garbage collector pour s'exécuter. Tout ce qu'il fait est de retirer (explicitement) une copie potentielle d'une référence de la prochaine fois que le garbage collector est exécuté. Enfin, si nous supposons que la portée est la suivante, alors la ligne C n'aura aucun effet discernable ... sauf si la ligne A ou la ligne B déclenche un garbage collection.

{ 
    MyObject myObj; 
    ArrayList arList = new ArrayList(); 
    while (someCondition) {  // A 
     myObj = new MyObect(); // B 
     arList.add(myObj); 
     myObj = null;   // C 
    } 
} 
+0

Oui, j'étais un peu confus à ce sujet, merci d'avoir dissipé mes doutes. Vous êtes géniaux les gars. –

Questions connexes