2008-11-26 13 views
10

Was im Speicher passiert, wenn eine Klasse folgendes Objekt instanziiert?Schritte in dem Speicherzuordnungsprozess für Java-Objekte

public class SomeObject{ 

    private String strSomeProperty; 

    public SomeObject(String strSomeProperty){ 
     this.strSomeProperty = strSomeProperty; 
    } 
    public void setSomeProperty(String strSomeProperty){ 
     this.strSomeProperty = strSomeProperty; 
    } 
    public String getSomeProperty(){ 
     return this.strSomeProperty; 
    } 
} 

In der Klasse SomeClass1:

SomeObject so1 = new SomeObject("some property value"); 

In der Klasse SomeClass2:

SomeObject so2 = new SomeObject("another property value"); 

Wie Speicher in das neu instanzierte Objekt und seine Eigenschaften zugeordnet ist?

Antwort

9

Lassen Sie uns Schritt für Schritt durch es:

SomeObject so1 = new SomeObject("some property value"); 

... ist eigentlich viel komplizierter als es aussieht, weil Sie einen neuen String sind zu schaffen. Es könnte einfacher sein, als zu denken:

String tmp = new String("some property value"); 
SomeObject so1 = new SomeObject(tmp); 
// Not that you would normally write it in this way. 

(Um absolut genau zu sein - das ist nicht wirklich gleichwertig Im Original der ‚neue String‘ wird bei der Kompilierung erstellt und einen Teil des .class- Bildes ist.. Sie können als Performance-Hack daran denken.)

Also, zuerst die JVM Platz für den String zuweist. In der Regel wissen oder interessieren Sie sich nicht für die Interna der String-Implementierung. Nehmen Sie also einfach an, dass ein Teil des Speichers verwendet wird, um "einen Eigenschaftswert" darzustellen. Außerdem haben Sie vorübergehend Speicher reserviert, der einen Verweis auf den String enthält. In der zweiten Form heißt es explizit tmp; In Ihrer ursprünglichen Form behandelt Java es, ohne es zu benennen.

Als nächstes weist die JVM Speicherplatz für ein neues SomeObject zu. Das ist ein wenig Platz für die interne Buchhaltung von Java und Platz für jedes der Felder des Objekts. In diesem Fall gibt es nur ein Feld, strSomeProperty.

Beachten Sie, dass strSomeProperty in einen String nur eine Referenz. Für jetzt wird es auf Null initialisiert.

Als nächstes wird der Konstruktor ausgeführt.

this.strSomeProperty = strSomeProperty; 

All dies tut, ist die Referenz zum String kopieren, in Ihre strSomeProperty Feld.

Schließlich Raum für die Objektreferenz so1 zugeordnet. Dies wird mit einem Verweis auf SomeObject festgelegt.

so2 Werke in genau der gleichen Weise.

+3

Nein, es ist nicht komplizierter als es aussieht. "a" und neuer String ("a") sind keine äquivalenten Ausdrücke. String-Literale werden vom Compiler interniert. Sie verursachen keine zusätzlichen Heapzuweisungen, wenn sie verwendet werden. – bendin

+0

http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.10.0 – bendin

+0

Touche :) Allerdings denke ich Internieren ist konzeptionell noch komplizierter als das, was ich beschrieben habe. Ich denke, die passende Antwort hängt von der Absicht der Frage ab. – slim

6

Determining Memory Usage in Java von Dr. Heinz M. Kabutz gibt eine genaue Antwort, sowie ein Programm, um die Speichernutzung zu berechnen. Der relevante Teil:

  1. Die Klasse dauert mindestens 8 Byte. Also, wenn Sie ein neues Objekt() sagen; Sie werden 8 Bytes auf dem Heap reservieren.
  2. Jedes Datenelement belegt 4 Byte, außer für lange und doppelte Bytes, die 8 Byte belegen.Selbst wenn das Datenelement ein Byte ist, dauert es immer noch 4 Bytes! Außerdem wird die Menge des verwendeten Speichers in 8-Byte-Blöcken erhöht. Also, wenn Sie eine Klasse haben, die ein Byte enthält, wird es 8 Bytes für die Klasse und 8 Bytes für die Daten aufnehmen, insgesamt 16 Bytes (stöhnend!).
  3. Arrays sind ein bisschen schlauer. Primitive werden in Arrays gepackt. Wenn Sie also ein Array von Bytes haben, nehmen sie jeweils ein Byte auf (wow!). Die Speicherauslastung steigt natürlich immer noch in 8-Byte-Blöcken.

Da die Menschen in den Kommentaren darauf hingewiesen haben, Streicher sind ein Sonderfall, weil sie interniert werden können. Sie können über den Platz, den sie aufnehmen, auf die gleiche Art und Weise nachdenken, aber bedenken Sie, dass das, was wie mehrere Kopien desselben Strings aussieht, tatsächlich auf dieselbe Referenz verweisen kann.

+1

Beachten Sie, dass dies 7 Jahre alt ist und auf empirischen Daten beruht, die zu diesem Zeitpunkt eine bestimmte JVM auf einem bestimmten Betriebssystem verwendeten (der Artikel sagt soviel). Wenn Sie nicht sicher sind, auf welcher JVM Sie laufen werden, können Sie nicht so präzise sein. – slim

+0

Guter Punkt. Ich wäre nicht überrascht, wenn einige Dinge, die früher 4 Bytes benötigten, 8 auf einer 64-Bit-Plattform benötigen. Das Programm ermittelt jedoch die Größe eines Objekts empirisch. Wenn Sie es auf der Ziel-VM ausführen, erhalten Sie eine präzise Antwort. –

+0

Das ist cool. Vielen Dank. – DragonBorn

3

Punkte zu beachten:

  1. Wenn eine Methode aufgerufen wird, ein Rahmen auf der Oberseite des Stapels erstellt wird.
  2. Sobald eine Methode die Ausführung abgeschlossen hat, kehrt der Steuerungsfluss zur aufrufenden Methode zurück und der entsprechende Stapelrahmen wird gelöscht.
  3. Lokale Variablen werden im Stapel erstellt.
  4. Instanzvariablen werden im Heap erstellt & sind Teil des Objekts, zu dem sie gehören.
  5. Referenzvariablen werden im Stapel erstellt.

Ref: http://www.javatutorialhub.com/java-stack-heap.html

+0

Pls Exalain auch über vorzeitige Gärung in Heap .. – Akash5288

+0

* Lokale * Referenzvariablen werden im Stapel erstellt. Referenz * instance members * werden im umhüllenden Objekt im Heap erstellt. Nichts davon beantwortet die Frage. – EJP