Performance-Frage: Klasse oder primitive Typen?

DarthShader

Erfahrenes Mitglied
Hallo,

ich habe eine Frage über die der Performance einer Anwendung bezüglich des Garbage Collectors.

Mein Programm ruft eine bestimmte Methode sehr oft auf - diese Methode erwartet als Parameter 3D-Koordinaten. Ich habe mir dazu eine Vektor-Klasse erstellt, was ja nahe liegt, um x, y und z Koordinaten zu kapseln.

Übergebe ich der Methode nun neue Koordinaten (was eben sehr häufig passiert) so mache ich:

Code:
meineMethode(new MeineVektorKlasse(x, y, z));

Es passiert also, dass ständig neue Objekte vom Typ "MeineVektorKlasse" angelegt werden, nur weil ich Koordinaten übergeben will. Vom Objektorientierten Aspekt aus durchaus sinnvoll - aber von der Performance? Ich meine, es werden hunderte, wenn nicht tausende dieser Objekte erstellt, irgendwann wird doch der Garbage Collector mal sagen, weg mit den überflüüsigen Objekten, die eh nicht mehr referenziert werden...

Wäre es also korrekt zu sagen, dass es von der Perfomance her besser wäre, mit primitiven Typen zu arbeiten, sprich

Code:
meineMethode(x, y, z);		// x, y und z sind vom typ float

zu benutzen? Oder macht die Aussage keinen Sinn, weil Java vielleicht die primitiven Typen ebenfalls intern in Klassen wrappt, und sowieso Objekte erstellt werden etc..?

Ich kenne die internen Arbeitsweisen von Java leider zu schlecht, um über dieses Thema irgendwas auszusagen und würde mich freuen, wenn ihr mir ein paar Tipps geben könntet.


Vielen Dank!
 
Also wenn deine Vektorklasse nur Attribute hat und keine Methoden dann macht es keinen Sinn. Schliesslich besteht eine Klasse aus Attributen und Methoden, die mit den Attributen arbeiten.
Eine Klasse benoetigt meiner Meinung nicht bedeutend mehr Ressourcen, aber dass erzeugen eines Objektes benoetigt natuerlich auch Speicher genauso wie der Garbage-Collector ganz schoen zu "knueppeln" hat.
Also wenn du nur die Klasse erstellt hast um die Daten zu kapseln, dann wuerde ich darauf verzichten.
 
Frage:
Willst du dein Programm nur bei dir betreiben oder willst du es frei zugänglich und somit möglich performant machen?

Empfehlung:
Ich würde sagen du solltest, wenn es denn möglich ist primitive typen verwenden, diese werden so wie ich das weiß nicht in ihre Hüllklassen gelegt und dann gespeichert, sondern direkt in den Arbeitsspeicher.

Grund:
Jeder pType (primitivetype) hat eine bestimt größe, abhängig vom Prozessor, die bei der Deklarierung (int a;) im Arbeitsspeicher reserviert wird, bei der zuweisung dann, wird in den reservierten Bereich geschrieben (a = 100;)
Hier ein Sizetable:

Typ |Speicherplatz
byte | 1 Byte
short | 2 Bytes
int | 4 Bytes
long | 8 Bytes

solche Listen gibt auch im Netz.

Erklärung (Objekte):
Bei Objekten ist es allerdings so, dass diese immer und immer wieder erzeugt und in den Speicher geschrieben werden, allerdings nur die Attribute, da die Operationen nur bei der Klasse stehen. Die Objekte bleiben so lange im Arbeitsspeicher bestehen wie eine Referenz auf die Objekte vorhanden ist, das bedeutet wenn du die Objekte nun in ein Vektor packst eher gesagt, wenn du die Referenz deines Objektes and den Vektor weitergibst, besteht diese immer noch und der Arbeitsspeicher wird voller und voller.

Ich hoffe mein Post hat dir weiter geholfen... (wer mich korrigieren will bzw kann soll mir bitte eine Message schreiben, denn ich will nicht dumm bleiben :-D)
 
@illaX:

Ja, meine Klasse besitzt natürlich etliche Methoden, die für einen Vektor wichtig sind, wie arithmetische Operatoren, Skalarprodukt etc...

@Shat:

Vielen Dank für Deine Erklärung, das wusste ich allerdings schon. Kurze Ergänzung: Die Größe von primitiven Typen ist systemabhängig (Stichwort Embedded...), aber im "Hausgebrauch" findet man z.Z. kaum andere andere Größe z.B. für Integer's als 32Bit.

Meine Frage geht wohl eher in die Richtung, wie der JIT Compiler arbeitet, d.h. ob er vielleicht irgendwas optimiert, wenn er merkt, dass man mit der Klasse nur die Werte übergibt oder sonstwas (natürlich sehr unwahrscheinlich, das Beispiel soll nur verdeutlichen, in welche Richtung meine Überlegungen gehen).

Ich gehe momentan ja auch davon aus, dass bei solchen Dingen primitive Typen einfach schneller sind. Da sie ja nicht vom GC aufgeräumt werden, dachte ich auch daran, dass Java vielleicht für primitive Typen auch so eine Art Stack verwendet, um zu entscheiden, dass ein reservierter Speicherplatz "freigegeben" werden kann, sobald die zugehörige Variable ihre Gültigkeit verliert. Denn von den primitiven Typen sollte der GC ja eigentlich nischt wissen...

Nagut, ich werde dann wohl mal beginnen, einige der kritischen Methoden umzuschreiben (es geht ja nicht nur um die Signaturen der Methoden sondern auch um deren Implementierung, weil ich dann ja keine Vektorklasse mehr zur Verfügung habe), ich hoffe das ist die richtige Entscheidung.
Falls irgendein Java Guru jetzt denkt "oh gott, was quatscht der da", dann bitte melde Dich schnell :p


Danke für Eure Hilfe
 
Hallo!

Die Erzeugung von kleinen kurzlebigen Objekten ist nicht teuer... der GC ist genau auf solche Faelle optimiert.

Gruss Tom
 
Thomas Darimont hat gesagt.:
Hallo!
Die Erzeugung von kleinen kurzlebigen Objekten ist nicht teuer... der GC ist genau auf solche Faelle optimiert.

Bedeutet das, Du würdest keinen Sinn darin sehen, primitive Typen zu sehen?

Was bedeutet kleines Objekt, das dürfte sich doch nur auf die Member Variablen beziehen, also Elemente die beim Instanzieren einer Klasse wirklich Speicher benötigen?
 
Hallo!

Schau mal hier:
http://www-128.ibm.com/developerworks/java/library/j-jtp09275.html?ca=dgr-lnxw07JavaUrbanLegends

Mit kleinen Objekten meine ich Objekte die wenig Speicher verbrauchen. Damit ist beispielsweise gemeint, dass die Objekte keine nativen/teuren Resourcen beherbergen (SWT-Shell, Images, Fonts.... Sockets, InputStreams) und nicht Teil eines grossen Objektnetzes sind. Fuer mich ist beispielsweise eine Instanz von java.awt.Point(...) ein "kleines" Objekt.

Weiterhin leben kleine kurzlebige Objekte innerhalb der Young Generation des Heaps
(Dieser setzt sich zusammen aus dem Eden Bereich und den beiden Survivor Spaces)
Hier finden haeufig schnelle GCs statt. Ueberleben Objekte innerhalb von Eden diese
Collections, so werden sie in die naechste Bereich die (beiden) survivor Spaces
verschoben. Die GCs lauefe nennt man innerhalb der Young Generation minor collections.
Ueberleben die dortigen Objekte auch diese Collections, so werden sie in die sogenannte
tenured Generation verschoben. Collections (hier major collections) im tenured space dauern
schon ein wenig laneger als die vorherigen. Daneben gibt es noch den speziellen Perm Bereich.
Hier findet nur noch selten eine aufwendige GC statt. Im Perm landen ueberwiegend Klassen,
Reflection Artefakte und kompilierte Methoden-Koerper.

Beim Flyweight Pattern wird ein Teile der Daten zwischen mehreren Instanzen geshared.

Gruss Tom
 
Thomas Darimont hat gesagt.:

Ich kann die Seite leider nicht erreichen, url falsch? Oder z.Z. einfach nicht erreichbar?

Auf jeden Fall danke für diese interessante Diskussion. Ich sollte mich vielleicht einmal näher mit den GC Mechanismen auseinander setzen. Ich denke, ich werde einmal versuchen, eine Art Benchmark in meinem speziellen Fall durchzuführen, um zu sehen, ob es mir wirklich Vorteile bringt.

Flyweights sind auch nen interessantes Pattern, ob ich das nun für meine Vektor Klasse baue, oder der Nutzen nicht den Aufwand rechtfertigt, muss ich noch entscheiden.


Vielleicht noch eine kleine Frage hinterher, die nicht unbedingt exakt in diesen Thread passt, aber wo wir schonmal dabei sind: Wenn man die Geschwindigkeit eines Java Programmes analysieren will, nehmen wir an, das Programm verursacht alle n-Sekunden irgendwelche kleinen "Aussetzer" und möchte nun ermitteln, was dies verursacht, gibt es da irgendwelche guten Möglichkeiten/Ansätze? Ich habe mal irgendwo etwas von "Profilern" gehört, gibts da irgendwas, oder habe ich mich verhört? :)
 
Zurück