2013-08-02 6 views
13

Ich war vor kurzem in freien Speicher durch Java-Objekte belegt suchen. Während ich das tat, war ich verwirrt darüber, wie Objekte in Java kopiert werden (flach/tief) und wie vermieden werden kann, dass Objekte versehentlich gelöscht/annulliert werden, während sie noch benutzt werden.Löschen oder Null auf Objekte in Java setzen

Betrachten folgende Szenarien:

  1. ein ArrayList<Object> als Argument für eine Methode übergeben.
  2. übergibt eine ArrayList<Object> an eine ausführbare Klasse, die von einem Thread verarbeitet werden soll.
  3. setzen Sie eine ArrayList<Object> in eine HashMap.

Jetzt, in diesem Fall, wenn ich list = null; oder list.clear(); aufrufen, was passiert mit den Objekten? In diesem Fall gehen die Objekte verloren und in welchen Fällen wird nur die Referenz auf Null gesetzt?

Ich denke, es hat mit seichtem und tiefem Kopieren von Objekten zu tun, aber in welchen Fällen geschieht flaches Kopieren und in welchem ​​Fall findet tiefes Kopieren in Java statt?

+1

Ich fand immer eine der attraktivsten Aspekte der Java der Garbage Collector ist ... –

Antwort

36

Zuerst setzen Sie nie ein Objekt auf Null. Dieses Konzept hat keine Bedeutung. Sie können einen Wert von null einer Variablen zuweisen, aber Sie müssen sehr sorgfältig zwischen den Begriffen "Variable" und "Objekt" unterscheiden. Sobald Sie das tun, wird Ihre Frage sich selbst beantworten :)

Jetzt in Bezug auf "seichte Kopie" vs "Deep Copy" - es ist wahrscheinlich wert, den Begriff "flache Kopie" hier zu vermeiden, wie in der Regel eine flache Kopie beinhaltet erstellen ein neues Objekt, aber nur die Felder eines vorhandenen Objekts direkt kopieren. Eine tiefe Kopie würde eine Kopie der Objekte, auf die sich diese Felder beziehen, ebenfalls übernehmen (für Referenztyp-Felder). Eine einfache Zuordnung wie folgt aus:

ArrayList<String> list1 = new ArrayList<String>(); 
ArrayList<String> list2 = list1; 

... macht nicht entweder eine flache Kopie oder eine tiefe Kopie in diesem Sinne. Es kopiert nur die Referenz. Nach dem obigen Code sind list1 und list2 unabhängige Variablen - sie haben zufällig die gleichen Werte (Referenzen). Wir könnten den Wert einer von ihnen ändern, und es würde die anderen nicht beeinflussen:

list1 = null; 
System.out.println(list2.size()); // Just prints 0 

Nun, wenn anstelle der Änderung der Variablen wir eine Änderung an dem Objekt machen, dass die Variablen Werte beziehen sich auf , wird diese Änderung über die andere Variable zu sehen sein:

list2.add("Foo"); 
System.out.println(list1.get(0)); // Prints Foo 

auf Ihre ursprüngliche Frage Also zurück - man kann nie eigentlichen Objekte speichern in einer Karte, Liste, Array etc. Sie immer nur Referenzen speichern.Ein Objekt kann nur dann als Müll gesammelt werden, wenn es keine Möglichkeit mehr gibt, wie "lebendiger" Code dieses Objekt erreichen kann. Also in diesem Fall:

List<String> list = new ArrayList<String>(); 
Map<String, List<String>> map = new HashMap<String, List<String>>(); 
map.put("Foo", list); 
list = null; 

... das ArrayList Objekt kann immer noch nicht Müll gesammelt werden, da die Map einen Eintrag hat, die es sich bezieht.

+0

thnks zum Löschen hat nichts mit seichtem oder tiefem Kopieren zu tun !! – anzaan

1

Es hängt davon ab, wie viele Variablen zu jedem Ihrer Objekte referenciating, dies zu erklären, es würde einige Code besser sein:

Object myAwesomeObject = new Object(); 
List<Object> myList = new ArrayList<Object>(); 

myList.add(myAwesomeObject); 

myList = null; // Your object hasn't been claimed by the GC just yet, your variable "myAwesomeObject" is still refering to it 

myAwesomeObject = null; // done, now your object is eligible for garbage collection. 

So ist es nicht davon ab, ob Sie Ihre Arraylist als Argument übergeben zu Eine Methode oder ähnliches hängt davon ab, wie viele Variablen sich noch auf Ihre Objekte beziehen.

+0

Sie haben vergessen: 'myList.add (myAwesomeObject); ':))) – alfasin

+0

DUH !!! Danke @alfasin – morgano

1

Wenn Sie die Liste in eine Hash-Map einfügen, enthält die Hash-Map jetzt einen Verweis auf die Liste.

Wenn Sie die Liste als Argument an eine Methode übergeben, hat die Methode für die Dauer der Methode einen Verweis darauf.

Wenn Sie es an einen zu manipulierenden Thread übergeben, erhält der Thread einen Verweis auf das Objekt, bis es beendet wird.

Wenn Sie in diesen Fällen list = null festlegen, werden die Referenzen weiterhin beibehalten, aber sie verschwinden, sobald diese Referenzen nicht mehr vorhanden sind.

Wenn Sie die Liste einfach löschen, sind die Referenzen immer noch gültig, zeigen aber jetzt auf eine Liste, die plötzlich geleert wurde. Dies kann dem Programmierer unbekannt sein und kann als Fehler angesehen werden, besonders wenn Sie Benutze den Thread.

1

Java GC beansprucht die Objekte automatisch, wenn sie nirgendwo referenziert werden. In den meisten Fällen müssen Sie also die Referenz als null explizit setzen

Sobald der Gültigkeitsbereich der Variablen endet, wird das Objekt für GC zugelassen und wird freigegeben, wenn kein anderer Verweis auf das Objekt zeigt.

Java ist Pass von Wert so, wenn Sie die Liste als null in dem Verfahren, dann wird es nicht die ursprüngliche Referenz beeinflussen, die für Sie in der Methode übergeben wurden.

public class A{ 

    private List<Integer> list = new ArrayList<Integer>(); 
    public static void main(String[] args) { 
     A a = new A(); 
     B b = new B(); 

     b.method(a.list); 

     System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException 
    } 

} 

class B{ 
    public void method(List<Integer> list){ 
     list = null; 
     //just this reference is set to null and not the original one 
     //so list of A will not be GCed 
    } 
} 
1

Wenn Sie eine Arraylist ein Verfahren dann Liste übergeben = null keine Wirkung, wenn es ein Live-Verweis auf die Liste in dem anrufenden Code irgendwo zB ist. Wenn Sie list.clear() an einer beliebigen Stelle im Code aufrufen, werden die Verweise auf die Objekte aus dieser Liste auf Null gesetzt. Einen Verweis auf eine Methode zu übergeben ist nicht seichtes Kopieren ist die Weitergabe von Referenz-Wert

0

Ich war vor kurzem in freien Speicher durch Java-Objekte belegt suchen.

Ein Ratschlag.

Es ist normalerweise eine schlechte Idee darüber nachzudenken. Und es ist normalerweise eine schlechtere Idee zu versuchen, "zu helfen". In 99,8% der Fälle ist der Java-Garbage Collector in der Lage, den Müll besser zu sammeln, wenn Sie ihn einfach weitermachen ... und verschwenden nicht Ihren Aufwand, indem Sie den Dingen null zuweisen. In der Tat sind die Chancen, dass die Felder, die du annulierst, in Objekten sind, die sowieso unerreichbar werden. Und in diesem Fall wird der GC nicht einmal die Felder ansehen, die Sie nulled haben.

Wenn Sie diese (pragmatische) Sichtweise betrachten, ist es völlig egal, ob Sie über flache oder tiefe Kopien nachdenken und wann es sicher ist, die Dinge auf Null zu setzen.


Es gibt einen kleinen Prozentsatz der Fälle, in denen es sinnvoll ist null zuweisen ... mittel- oder langfristige Lagerung Lecks zu vermeiden. Und wenn Sie in einer der seltenen Situationen sind, in denen es "recycling" Objekte ist eigentlich eine gute Idee, dann ist auch Nullen ratsam.

4

die Variable

Nach meinem Wissen zu löschen,

Wenn Sie die Variable wieder verwenden werden, dann

   Object.clear(); 

verwenden Wenn Sie nicht wieder zu verwenden gehen , dann definieren

   Object=null; 

Hinweis: Vergleichen Sie mit removeAll(), clear() ist schneller.

Bitte korrigieren Sie mich, wenn ich falsch bin ....