2016-08-02 27 views
4

Wenn sich ein Objekt im Heap befindet und dieses Objekt einige Instanzvariablen hat, sind einige primitive Typen und wenige sind andere Objekte. Also, wenn dieses Objekt 5 Felder hat, wie ist das Objekt im Speicher strukturiert? Um genau zu sein ... wo speichert Java den Datentyp jedes Feldes? Gibt es einige 'Flag-Bytes' und einige 'Daten-Bytes', wobei die 'Flag-Bytes' den Datentyp der nächsten 'Daten-Bytes' identifizieren?Wie erkennt Java, ob eine Position primitiv oder referenziert ist

ich einige zusätzliche Details beziehe mich über diese Antwort fortfahren: https://stackoverflow.com/a/19623603/1364747

Diese Antwort wirft viel mehr Detail, wie die Daten selbst im Speicher abgelegt wird: https://stackoverflow.com/a/1907455/1364747

es gibt aber noch nicht Sagen Sie, wo das Flag gespeichert ist, das besagt, dass der Datentyp int/long/double/float/reference ist.

+3

Bezieht sich dies auf die In-Memory-Darstellung? Ich denke, dass dies weitgehend der Umsetzung überlassen bleibt. Tatsächlich glaube ich, dass, sobald die JVM eine Klassendatei geladen hat, die als * gültig * bestimmt wurde, streng genommen, muss sie diese Information nicht zusammen mit den tatsächlichen Instanzdaten "speichern". Es ist einfach nicht relevant für die Ausführung. Wenn die Instanz introduziert ist (z. B. mit Reflexion), kann die Information in den Klassendaten nachgeschlagen werden. Und ... da ist es: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-FieldType – Marco13

+0

Ich kenne die Antwort auf diese Frage nicht, aber in der Assemblersprache wird, ob ein Datenstück als ein Zeiger oder als ein Seitenwert interpretiert wird, durch die Art von Anweisungen bestimmt, die auf diese Daten einwirken. Wenn ich dies auf Java ausweite, würde ich raten, dass, wenn Java den Code in Bytecode kompiliert, er Bytecode-Anweisungen kompiliert, um Referenztypen als Zeiger auf andere Speicherstellen und primitive Typen als Gesichtswerte zu behandeln. Dies ist jedoch eine vollständige Schätzung. – jrahhali

+0

Okay. Also könnte grob JVM-Implementierung 20 Bytes zusammenhängender Daten im Speicher speichern, und welches Byte sollte als int interpretiert werden und welche Bytes sollten als double-part1 interpretiert werden und double-part2 würde von der Klasse bezogen werden? Oder es könnte in JVM-spezifischer Weise für die Leistung behandelt werden .. ok. – Teddy

Antwort

1

Hier ist eine konkretere Antwort, die ich fürchte immer noch nicht beantwortet alle Ihrer Frage. Hier ist der Link aus der Java-7-Dokumentation, mit dem entsprechenden Abschnitt zu sein "2.11 Instruction Set Zusammenfassung.": https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html

ich kopiere & einen Teil davon ein:

2.11.1. Typen und die Java Virtual Machine

Die meisten der Anweisungen in der Java Virtual Machine-Befehlssatz kodieren Art Informationen über die Operationen, die sie ausführen. Für Instanz lädt die iload-Anweisung (§iload) den Inhalt einer lokalen -Variablen, die ein int sein muss, auf den Operandenstapel. Die Anweisung fload (§fload) tut dasselbe mit einem Gleitkommawert. Die zwei Anweisungen können identische Implementierungen haben, aber unterschiedliche Opcodes haben.

Für die Mehrheit der getippten Anweisungen, ist der Befehlstyp explizit in dem Opcode mnemonic durch einen Buchstaben dargestellt wird: i für einen int Betrieb, l für lange, s für kurze, b für Byte, c für char, f für float, d für double, und a als Referenz.

2.11.2. Lade- und Speicherbefehle

Die Lade- und Speicherbefehle Übertragungswerte zwischen den lokalen Variablen (§2.6.1) und der Operandenstapel (§2.6.2) einer Java Virtual Maschinenrahmen (§2.6).

Anweisungen, die auf Felder von Objekten und Elemente von Arrays zugreifen (§2.11.5) übertragen auch Daten zum und vom Operandenstapel.

Da ist noch viel mehr. Interessantes lesen.

+0

Danke. Das macht es so deutlich. Ich hatte das immer als Grauzone. Ich werde auch die Dokumente durchgehen, um mehr Verständnis zu bekommen. – Teddy

1

Typinformationen werden nur zur Kompilierzeit benötigt, um den korrekten Bytecode zu generieren. Bytecode-Anweisungen (wie Assembler-Anweisungen) können typischerweise nur auf einen Datentyp angewendet werden.Somit spiegelt der verwendete Befehl den Typ der Operanden wider. Dies gilt für die meisten Sprachen der C-Familie.

Um zu sehen, wie der Bytecode bei der Verwendung eines Primitivs und einer dynamischen Zuweisung in Aktion gehen würde, nehmen wir ein einfaches Beispiel.

public static void main (String [] args) { 
    int i = 0; 
    int j = i + 1; 
} 

Und der Bytecode erzeugt:

public static void main(java.lang.String[]); 
    Code: 
    0: iconst_0 
    1: istore_1 
    2: iload_1 
    3: iconst_1 
    4: iadd 
    5: istore_2 
    6: return 

So speichern wir und die ganzen Zahlen laden istore und iload verwenden, und dann fügen wir sie iadd (i für integer) verwendet wird.

nun dieses Beispiel nehmen, eine dynamische Speicherzuweisung anstelle eines primitiven:

public static void main (String [] args) { 
    Integer i = new Integer(0); 
    int j = i + 1; 
} 

Und den Bytecode:

public static void main(java.lang.String[]); 
    Code: 
    0: new   #2     // class java/lang/Integer 
    3: dup 
    4: iconst_0 
    5: invokespecial #3     // Method java/lang/Integer."<init>":(I)V 
    8: astore_1 
    9: aload_1 
    10: invokevirtual #4     // Method java/lang/Integer.intValue:()I 
    13: iconst_1 
    14: iadd 
    15: istore_2 
    16: return 

In dieser Version müssen wir zunächst die intValue() Methode aufrufen das Integer Objekt, um den Wert abzurufen, und dann können wir über iadd darauf handeln.

Und für den Beweis, dass Datentypen nicht nach der Kompilierung gespeichert werden müssen (da sie in den Anweisungen selbst codiert sind, wie istore für "Ganzzahlspeicher"), siehe die Referenz in Jrahhalis Antwort.