Sollten wir die Objekterstellung in Java vermeiden?


243

Ein Kollege sagte mir, dass die Erstellung von Java-Objekten die teuerste Operation ist, die Sie ausführen können. Daraus kann ich nur den Schluss ziehen, so wenig Objekte wie möglich zu erstellen.

Dies scheint den Zweck der objektorientierten Programmierung etwas zu entkräften. Wenn wir keine Objekte erstellen, schreiben wir nur einen langen C-Stil zur Optimierung.


39
Msgstr "Die Java - Objekterstellung ist die teuerste Operation, die Sie durchführen können" . Teilen Sie die Quelle dieser Behauptung?
Songo

92
Und - teuerste Operation im Vergleich zu was? Im Vergleich zur Berechnung von pi auf 900 Stellen oder zur Erhöhung eines int?
Jasonk

4
Könnten sie über einen bestimmten Teil dieser bestimmten Objekterstellung gesprochen haben? Ich denke, wie Apple eine Warteschlange für tableViewCells verwendet. Vielleicht hat Ihr Kollege vorgeschlagen, einige Objekte zu erstellen und sie wiederzuverwenden, da mit diesen bestimmten Objekten ein gewisser Aufwand verbunden ist? Ich versuche nur herauszufinden, warum sie einen solchen Anspruch erheben würden.
Tyler DeWitt

3
Dies ist eines der
lustigsten

22
Arithmetik ist auch ziemlich teuer; Wir sollten Berechnungen vermeiden, oh, und das Starten einer JVM ist sehr teuer, daher sollten wir keine JVMs starten :-).
James Anderson

Antworten:


478

Ihr Kollege hat keine Ahnung, wovon er spricht.

Ihre teuerste Operation wäre es, ihnen zuzuhören . Sie haben Ihre Zeit damit verschwendet, Sie zu Informationen zu verleiten, die mehr als ein Jahrzehnt veraltet sind (ab dem ursprünglichen Datum, an dem diese Antwort veröffentlicht wurde), und Sie mussten Zeit damit verbringen, hier zu posten und im Internet nach der Wahrheit zu suchen.

Hoffentlich erbrechen sie etwas, das sie vor mehr als einem Jahrzehnt gehört oder gelesen haben, nur unwissentlich und wissen es nicht besser. Ich würde alles andere, was sie sagen, auch als verdächtig ansehen. Dies sollte ein bekannter Irrtum von jedem sein, der so oder so auf dem Laufenden bleibt.

Alles ist ein Objekt (außer primitives)

Alles andere als Grundelemente ( int, long, doubleusw.) sind Objekte in Java. Es gibt keine Möglichkeit, die Objekterstellung in Java zu umgehen.

Die Objekterstellung in Java ist aufgrund seiner Speicherzuweisungsstrategien in den meisten Fällen schneller als in C ++ und kann für alle praktischen Zwecke im Vergleich zu allem anderen in der JVM als "frei" betrachtet werden .

Bereits in den frühen 2000er-Jahren der späten 1990er-Jahre hatten JVM-Implementierungen einen gewissen Performance-Overhead bei der tatsächlichen Zuweisung von Objekten. Dies ist seit mindestens 2005 nicht mehr der Fall.

Wenn Sie so einstellen -Xms, dass der gesamte für die ordnungsgemäße Ausführung Ihrer Anwendung erforderliche Arbeitsspeicher unterstützt wird, muss der GC in den modernen GC-Implementierungen möglicherweise nie ausgeführt und den größten Teil des Mülls beseitigt werden.

Es wird nicht versucht, den freien Speicherplatz zu maximieren, was ohnehin ein roter Hering ist, sondern es wird die Leistung der Laufzeit maximiert. Wenn dies bedeutet, dass der JVM-Heap fast immer zu 100% zugeordnet ist, ist dies auch der Fall. Freier JVM-Heapspeicher gibt Ihnen sowieso nichts, was Sie nur dort sitzen.

Es besteht ein Missverständnis, dass der GC auf nützliche Weise Speicher für den Rest des Systems freigibt. Dies ist völlig falsch!

Der JVM-Heap wächst und schrumpft nicht, sodass der Rest des Systems durch den freien Speicher im JVM-Heap positiv beeinflusst wird . -XmsWeist ALLES zu, was beim Start angegeben wird, und seine Heuristik besteht darin, nie wirklich etwas von diesem Speicher für das Betriebssystem freizugeben, um es mit anderen Betriebssystemprozessen zu teilen, bis diese Instanz der JVM vollständig beendet wird. -Xms=1GB -Xmx=1GBWeist 1 GB RAM zu, unabhängig davon, wie viele Objekte tatsächlich zu einem bestimmten Zeitpunkt erstellt wurden. Es gibt einige Einstellungen, mit denen Prozentsätze des Heapspeichers freigegeben werden können. In der Praxis kann die JVM jedoch nie genug Speicher freigeben, damit dies jemals passieren kannDaher kann kein anderer Prozess diesen Speicher zurückfordern, sodass auch der Rest des Systems nicht davon profitiert, dass der JVM-Heap-Speicher frei ist. Eine RFE dafür wurde am 29. November 2006 "akzeptiert" , aber es wurde noch nie etwas dagegen unternommen. Dieses Verhalten wird von niemandem mit Autorität als bedenklich angesehen.

Es gibt ein Missverständnis, dass das Erstellen vieler kleiner, kurzlebiger Objekte dazu führt, dass die JVM für längere Zeit pausiert. Dies ist nun ebenfalls falsch

Derzeitige GC-Algorithmen sind für die Erstellung vieler kleiner Objekte mit kurzer Lebensdauer optimiert. Dies ist im Grunde die 99% -ige Heuristik für Java-Objekte in jedem Programm. Versuche, Objekte zusammenzufassen , führen in den meisten Fällen zu einer Verschlechterung der Leistung der JVM.

Die einzigen Objekte, die heute gepoolt werden müssen, sind Objekte, die sich auf endliche Ressourcen außerhalb der JVM beziehen . Sockets, Dateien, Datenbankverbindungen usw. können wiederverwendet werden. Regelmäßige Objekte können nicht werden gepoolt im gleichen Sinne wie in Sprachen , die Sie direkten Zugriff auf Speicherplätze ermöglichen. Objekt- Caching ist ein anderes Konzept und kann oder kann nicht das sein, was manche Leute naiv als Pooling bezeichnen . Die beiden Konzepte sind nicht dasselbe und sollten nicht miteinander verschmolzen werden.

Die modernen GC-Algorithmen haben dieses Problem nicht, da sie nicht nach einem Zeitplan freigegeben werden, sondern freigegeben werden, wenn in einer bestimmten Generation freier Speicher benötigt wird. Wenn der Heap groß genug ist, werden die Zuordnungen nicht lange genug aufgehoben, um Pausen zu verursachen.

Objektorientiert Dynamische Sprachen schlagen C auch heute noch bei rechenempfindlichen Tests.


274
+1: "Ihre teuerste Operation wäre es, ihnen zuzuhören ...". Das Beste, was ich seit einiger Zeit gehört habe.
rjnilsson

21
@DeadMG, auch mit dem kumulativen GC - Overhead, Java kann schneller als C ++ (zB aufgrund der Heap - Verdichtung, Cache - Misses für bestimmte Datenstrukturen zu minimieren).
SK-logic

13
@ SK-logic: Da der GC nicht deterministisch ist, ist es allenfalls äußerst schwierig, dies tatsächlich zu beweisen. Das Minimieren von Cache-Fehlern ist schwierig, wenn jedes Objekt eine andere Indirektion sein muss, wodurch Cache-Speicherplatz verschwendet und die Ausführungszeit verlängert wird. Ich behaupte jedoch, dass Sie die Leistung des Garbage Collectors leicht erreichen oder übertreffen können, indem Sie einfach einen geeigneten Allokator in C ++ wie einen Objektpool oder eine Speicherarena verwenden. Beispielsweise können Sie eine Memory-Arena-Klasse schreiben, die schneller als _allocaamortisiert arbeitet.
DeadMG

33
Die Objekterstellung ist jetzt billiger als früher. Es ist jedoch nicht kostenlos. Wer dir das sagt, lügt. Und der Link über OO-Sprachen, die C schlagen, ist eine übertriebene Reaktion auf jemanden, der wirklich versucht zu lernen.
Jasonk

17
Aufgrund dieser Art von Antworten erhalten wir einen beschissenen Code. Die richtige Antwort ist, ein Objekt in Java zu erstellen, das Java-Objekt zu erstellen und es zu initialisieren. Der erste Teil ist billig, der zweite kann sehr teuer sein. Die Leute sollten sich immer ansehen, was in Konstruktoren passiert, bevor sie das newSchlüsselwort an einem Hotspot verwenden. Ich habe Leute verwenden gesehen new ImageIcon(Image)in der paint()Methode der Swing - Objekte, die ziemlich teuer ist und war die gesamte UI Super träge macht. Es ist also keine Schwarz-Weiß-Antwort. Überlegen Sie, bevor Sie sie newirgendwo verwenden.
Qwertzguy

94

Fazit: Gehen Sie keine Kompromisse bei Ihrem Design ein, um Verknüpfungen zum Erstellen von Objekten zu erstellen. Vermeiden Sie es, unnötig Objekte zu erstellen. Wenn sinnvoll, sollten Sie redundante Vorgänge (jeglicher Art) vermeiden.

Im Gegensatz zu den meisten Antworten - ja, die Objektzuweisung ist mit Kosten verbunden. Es ist kostengünstig, aber Sie sollten vermeiden, unnötige Objekte zu erstellen. Das Gleiche, wie Sie unnötige Elemente in Ihrem Code vermeiden sollten. Große Objektdiagramme verlangsamen die GC, was längere Ausführungszeiten mit sich bringt, da Sie wahrscheinlich mehr Methodenaufrufe haben, mehr CPU-Cache-Ausfälle auslösen und die Wahrscheinlichkeit erhöhen, dass Ihr Prozess in Fällen mit geringem Arbeitsspeicher auf die Festplatte ausgelagert wird.

Bevor sich jemand darüber beschwert, dass dies ein Randfall ist, habe ich Anwendungen profiliert, die vor der Optimierung 20 + MB Objekte erstellt haben, um ~ 50 Datenzeilen zu verarbeiten. Dies ist beim Testen in Ordnung, bis Sie auf 100 Anforderungen pro Minute skalieren und plötzlich 2 GB Daten pro Minute erstellen. Wenn Sie 20 Reqs / Sek. Ausführen möchten, erstellen Sie 400 MB Objekte und werfen sie dann weg. 20 reqs / sec ist für einen anständigen Server winzig.


7
Ich kann ein Beispiel hinzufügen: In einigen Fällen macht es keinen Unterschied in Bezug auf die Klarheit des Codes, aber es kann einen mehr oder weniger großen Unterschied in der Leistung bewirken: Beim Lesen von Streams ist es beispielsweise nicht ungewöhnlich, so etwas wie while(something) { byte[] buffer = new byte[10240]; ... readIntoBuffer(buffer); ...das zu verwenden verschwenderisch im Vergleich zu z byte[] buffer = new byte[10240]; while(something) { ... readIntoBuffer(buffer); ....
JimmyB

4
+1: Unnötige Objekterstellung (oder vielmehr Aufräumen nach dem Entfernen) kann definitiv manchmal kostspielig sein. 3D-Grafik- / OpenGL-Code in Java ist einer der Bereiche, in denen Optimierungen vorgenommen wurden, um die Anzahl der erstellten Objekte zu minimieren, da GC andernfalls die Framerate beeinträchtigen kann.
Leo

1
Beeindruckend! Über 20 MB für die Verarbeitung von 50 Datenzeilen? Klingt verrückt. Sind diese Objekte auf jeden Fall langlebig? Denn das ist der Fall, der für GC von Bedeutung wäre. Wenn Sie auf der anderen Seite lediglich die Speicheranforderungen diskutieren , hat dies nichts mit der Speicherbereinigung oder der Effizienz der Objekterstellung zu tun ...
Andres F.

1
Objekte sind kurzlebig (im allgemeinen Fall weniger als 0,5 Sekunden). Dieses Müllvolumen wirkt sich immer noch auf die Leistung aus.
Jasonk

2
Vielen Dank, dass Sie tatsächlich der Realität treu bleiben. Jeder, der mit den Auswirkungen einer gedankenlosen Architektur lebt, kann sehr viel erzählen.
JM Becker

60

Aufgrund der Speicherverwaltungsstrategien, die die Java-Sprache (oder eine andere verwaltete Sprache) ermöglicht, ist die Objekterstellung kaum mehr als das Inkrementieren eines Zeigers in einem Speicherblock, der als junge Generation bezeichnet wird. Es ist viel schneller als C, wo nach freiem Speicher gesucht werden muss.

Der andere Teil der Kosten betrifft die Zerstörung von Objekten, ist aber schwer mit C zu vergleichen. Die Kosten einer Sammlung basieren auf der Menge der Objekte, die langfristig gespeichert wurden, aber die Häufigkeit der Sammlungen basiert auf der Menge der Objekte, die erstellt wurden Am Ende ist es immer noch viel schneller als die Speicherverwaltung im C-Stil.


7
+1 Auch wenn der Garbage Collector "nur funktioniert", sollte jeder Java-Programmierer etwas über den Garbage Collector der Generation lernen.
benzado

18
Die neueren Versionen von Java können Escape-Analysen durchführen, was bedeutet, dass sie Speicher für Objekte zuweisen können, die einer Methode auf dem Stapel nicht entgehen, sodass die Bereinigung kostenlos ist - der Garbage Collector muss sich nicht mit diesen Objekten befassen werden sie automatisch verworfen, wenn der Stapelrahmen der Methode aufgehoben wird (wenn die Methode zurückkehrt).
Jesper,

4
Ein nächster Schritt für die Escape-Analyse ist die "Zuweisung" von Speicher für kleine Objekte ausschließlich in Registern (zum Beispiel könnte ein PointObjekt in zwei Universalregister passen).
Joachim Sauer

6
@Joachim Sauer: So wird es in den neueren Implementierungen der HotSpot VM gemacht. Es heißt Skalarersatz.
Irgendwann

1
@someguy: Ich habe es vor einiger Zeit als nächstes gelesen, habe aber nicht nachgeprüft, ob es bereits fertig ist. Es ist eine gute Nachricht zu hören, dass wir das bereits haben.
Joachim Sauer

38

Andere Poster haben zu Recht darauf hingewiesen, dass die Objekterstellung in Java extrem schnell ist und dass Sie sich in einer normalen Java-Anwendung normalerweise keine Gedanken darüber machen sollten.

Es gibt ein paar ganz besondere Situationen , in denen sind ist eine gute Idee , Objekterstellung zu vermeiden.

  • Wenn Sie eine latenzempfindliche Anwendung schreiben und GC-Pausen vermeiden möchten. Je mehr Objekte Sie produzieren, desto mehr GC wird durchgeführt und desto größer ist die Wahrscheinlichkeit von Pausen. Dies kann eine wichtige Überlegung für Spiele, einige Medienanwendungen, Robotersteuerung, Hochfrequenzhandel usw. sein. Die Lösung besteht darin, alle Objekte / Arrays, die Sie im Voraus benötigen, vorab zuzuweisen und erneut zu verwenden. Es gibt Bibliotheken, die auf diese Art von Funktionen spezialisiert sind, z . B. Javolution . Aber wenn Sie sich wirklich für niedrige Latenz interessieren, sollten Sie C / C ++ / Assembler anstelle von Java oder C # verwenden :-)
  • Das Vermeiden von Boxed Primitives (Double, Integer etc.) kann unter bestimmten Umständen eine sehr vorteilhafte Mikrooptimierung sein. Da Primitive ohne Box (double, int usw.) den Overhead pro Objekt vermeiden, sind sie viel schneller für die CPU-intensive Arbeit wie die numerische Verarbeitung usw. Primitive Arrays sind in Java in der Regel sehr leistungsfähig alle anderen Arten von Objekten.
  • In Situationen mit eingeschränktem Arbeitsspeicher möchten Sie die Anzahl der (aktiven) Objekte minimieren, die erstellt werden, da jedes Objekt einen geringen Overhead verursacht (in der Regel 8 bis 16 Byte, abhängig von der JVM-Implementierung). In solchen Fällen sollten Sie eine kleine Anzahl großer Objekte oder Arrays zum Speichern Ihrer Daten vorziehen, anstatt eine große Anzahl kleiner Objekte.

3
Es ist erwähnenswert, dass mit der Escape-Analyse kurzlebige (begrenzte Lebensdauer) Objekte auf dem Stapel gespeichert werden können. Diese Objekte können kostenlos freigegeben werden. Ibm.com/developerworks/java/library/j-jtp09275/index.html
Richard Tingle

1
@Richard: Die Great Point-Escape-Analyse bietet einige sehr gute Optimierungen. Sie müssen jedoch vorsichtig sein, wenn Sie sich darauf verlassen: Es kann nicht garantiert werden, dass dies in allen Java-Implementierungen und unter allen Umständen geschieht. Sie müssen also häufig ein Benchmarking durchführen, um sicherzugehen.
Mikera

2
Eine zu 100% korrekte Escape-Analyse ist gleichbedeutend mit dem Problem des Anhaltens. Verlassen Sie sich in komplexen Situationen nicht auf Fluchtanalysen, da diese mitunter die falsche Antwort liefern.
Jules

Der erste und der letzte Punkt gelten nicht für kleine Objekte, die schnell freigegeben werden. Sie sterben in Eden ab (denken Sie an die Stapelzuordnung in C, ziemlich frei) und haben keinen Einfluss auf die GC-Zeiten oder die Speicherzuordnung. Die meisten Objekte in Java fallen in diese Kategorie und sind daher im Wesentlichen kostenlos. Der zweite Punkt ist noch gültig.
Bill K

17

In dem, was Ihr Kollege sagt, steckt ein Kern der Wahrheit. Ich schlage vor , respektvoll das Problem mit dem Objekt Schöpfung ist eigentlich Müll Sammlung . In C ++ kann der Programmierer genau steuern, wie der Speicher freigegeben wird. Das Programm kann so lange oder so kurz wie es möchte Rohöl akkumulieren. Darüber hinaus kann das C ++ - Programm den Crud mit einem anderen Thread als dem, der ihn erstellt hat, verwerfen. Somit muss der aktuell funktionierende Thread nie aufhören, um aufzuräumen.

Im Gegensatz dazu stoppt die Java Virtual Machine (JVM) Ihren Code regelmäßig, um nicht verwendeten Speicherplatz freizugeben. Die meisten Java-Entwickler bemerken diese Pause nie, da sie normalerweise selten und sehr kurz ist. Je mehr Rohstoffe Sie ansammeln oder je eingeschränkter Ihre JVM ist, desto häufiger treten diese Pausen auf. Sie können Tools wie VisualVM verwenden , um diesen Prozess zu visualisieren.

In neueren Versionen von Java kann der Garbage Collection (GC) -Algorithmus optimiert werden . Je kürzer die Pausen sein sollen, desto teurer ist in der Regel der Overhead in der virtuellen Maschine (dh die CPU und der Speicher müssen für die Koordinierung des GC-Prozesses aufgewendet werden).

Wann könnte das von Bedeutung sein? Immer wenn Sie sich für gleichbleibende Sub-Millisekunden-Antwortraten interessieren, interessiert Sie GC. In Java geschriebene automatisierte Handelssysteme optimieren die JVM stark, um Pausen zu minimieren. Unternehmen, die sonst Java schreiben würden, greifen auf C ++ zurück, wenn Systeme ständig sehr reaktionsschnell sein müssen.

Ich kann das Vermeiden von Objekten im Allgemeinen nicht gutheißen! Standardmäßig wird die objektorientierte Programmierung verwendet. Passen Sie diesen Ansatz nur an, wenn der GC Ihnen im Weg ist, und erst dann, wenn Sie versuchen, die JVM so zu optimieren, dass sie eine kürzere Pause einlegt. Ein gutes Buch über Java Performance Tuning ist Java Performance von Charlie Hunt und Binu John.


10
Die meisten modernen JVMs unterstützen bessere Garbage Collection-Algorithmen als "Stop the World". Die amortisierte Zeit, die für die Speicherbereinigung aufgewendet wird, ist häufig geringer als die Zeit, die explizit für den Aufruf von malloc / free aufgewendet wird. Läuft die C ++ - Speicherverwaltung auch in einem separaten Thread?

10
Die neueren Java-Versionen von Oracle können Escape-Analysen durchführen. Dies bedeutet, dass Objekte, die einer Methode nicht entgehen, auf dem Stapel zugeordnet werden. Dadurch werden sie kostenlos bereinigt und automatisch freigegeben, wenn die Methode zurückgegeben wird.
Jesper

2
@ ThorbjørnRavnAndersen: Wirklich? Meinen Pause- Sie wirklich weniger GC, oder meinst du "in der Regel parallel-but-manchmal-a-tiny-Bit-Pause" GC? Ich verstehe nicht, wie der GC ein Programm niemals anhalten und gleichzeitig Objekte verschieben kann ... es scheint mir buchstäblich unmöglich ...
Mehrdad

2
@ ThorbjørnRavnAndersen: Wie kann es "die Welt stoppen", aber niemals "die JVM anhalten"? Das macht keinen Sinn ...
Mehrdad

2
@ ThorbjørnRavnAndersen: Nein, das weiß ich wirklich nicht. Ich verstehe nur nicht, was du sagst. Entweder pausiert der GC das Programm manchmal, in welchem ​​Fall es per Definition nicht "pausenlos" ist, oder er pausiert das Programm nie (daher ist es "pausenlos"), in welchem ​​Fall ich nicht verstehe, wie das ist Entspricht Ihrer Aussage "Es stoppt die Welt, wenn es nicht mithalten kann", da dies bedeuten würde, dass das Programm angehalten ist, während der GC in Betrieb ist. Würde es Ihnen etwas ausmachen zu erklären, was der Fall ist (ist es pausenlos oder nicht?) Und wie dies möglich ist?
Mehrdad


9

Der GC ist auf viele kurzlebige Objekte abgestimmt

das heißt, wenn Sie die Objektzuordnung trivial reduzieren können, sollten Sie

Ein Beispiel wäre das Bauen eines Strings in einer Schleife, der naive Weg wäre es

String str = "";
while(someCondition){
    //...
    str+= appendingString;
}

Hierdurch Stringwird für jede +=Operation ein neues Objekt erstellt (plus ein StringBuilderund das neue zugrunde liegende Zeichenarray).

Sie können dies leicht umschreiben in:

StringBuilder strB = new StringBuilder();
while(someCondition){
    //...
    strB.append(appendingString);
}
String str = strB.toString();

Dieses Muster (unveränderliches Ergebnis und ein lokal veränderlicher Zwischenwert) kann auch auf andere Dinge angewendet werden

Ansonsten sollten Sie einen Profiler aufrufen, um den echten Engpass zu finden, anstatt Geister zu jagen


der größte Vorteil in diesem StringBuilderAnsatz ist die vorge Größe der StringBuilderso dass es nie zu hat umverteilen den zugrunde liegenden Array mit dem StringBuilder(int)Konstruktor. Dies macht es zu einer einzelnen Zuordnung und nicht zu einer 1+NZuordnung.

2
@JarrodRoberson StringBuilder wird die aktuelle Kapazität mindestens verdoppeln, oder mit anderen Worten, die Kapazität wird nur für log (n) -Zuweisungen exponentiell ansteigen
Ratschenfreak

6

Joshua Bloch (einer der Entwickler der Java-Plattform) schrieb 2001 in seinem Buch Effective Java :

Das Vermeiden der Objekterstellung durch Verwalten Ihres eigenen Objektpools ist eine schlechte Idee, es sei denn, die Objekte im Pool sind extrem schwergewichtig. Ein prototypisches Beispiel für ein Objekt, das einen Objektpool rechtfertigt, ist eine Datenbankverbindung. Die Kosten für den Verbindungsaufbau sind so hoch, dass eine Wiederverwendung dieser Objekte sinnvoll ist. Im Allgemeinen wird Ihr Code jedoch durch die Verwaltung Ihrer eigenen Objektpools unübersichtlich, der Speicherbedarf wird erhöht und die Leistung wird beeinträchtigt. Moderne JVM-Implementierungen verfügen über hochoptimierte Garbage Collectors, die solche Objektpools für leichte Objekte problemlos übertreffen.


1
Selbst bei Dingen wie der Netzwerkverbindung ist es nicht wichtig, die GC-zugewiesenen Objekte zu verwalten, die den Verbindungen zugeordnet sind, sondern die Menge der Verbindungen, die außerhalb der GC-verwalteten Welt bestehen. Es gibt Zeiten, in denen das Zusammenfassen von Objekten selbst hilfreich sein kann. Die meisten davon stammen aus Fällen, in denen ein Paar von Verweisen auf dasselbe Objekt einem Paar von Verweisen auf identische, aber unterschiedliche Objekte semantisch äquivalent sein kann, aber dennoch einige Vorteile aufweist. Beispielsweise können zwei Verweise auf dieselbe Zeichenfolge mit fünfzigtausend Zeichen auf Gleichheit überprüft werden ...
supercat

2
... viel schneller als Verweise auf zwei unterschiedliche, aber identische Zeichenfolgen dieser Länge.
Supercat

5

Dies hängt wirklich von der spezifischen Anwendung ab, daher ist es im Allgemeinen sehr schwer zu sagen. Ich wäre jedoch ziemlich überrascht, wenn die Objekterstellung tatsächlich ein Leistungsengpass in einer Anwendung wäre. Selbst wenn sie langsam sind, überwiegt der Vorteil des Code-Stils wahrscheinlich die Leistung (es sei denn, der Benutzer merkt es tatsächlich.)

In jedem Fall sollten Sie sich nicht einmal Gedanken über diese Dinge machen, bis Sie Ihren Code profiliert haben, um die tatsächlichen Leistungsengpässe zu ermitteln, anstatt zu raten. Bis dahin sollten Sie alles tun, was für die Lesbarkeit des Codes am besten ist, nicht die Leistung.


In früheren Java-Versionen sind erhebliche Kosten entstanden, als der Garbage Collector weggeworfene Objekte bereinigte. In neueren Versionen von Java wurden die GC-Optionen erheblich erweitert, sodass die Objekterstellung selten ein Problem darstellt. In der Regel werden Web-Systeme durch E / A-Aufrufe an externe Systeme eingeschränkt, es sei denn, Sie berechnen beim Laden der Seite etwas wirklich Komplexes auf dem Anwendungsserver.
Greg

3

Ich denke, Ihr Kollege muss aus der Perspektive der unnötigen Objekterstellung gesagt haben. Ich meine, wenn Sie häufig dasselbe Objekt erstellen, ist es besser, dieses Objekt gemeinsam zu nutzen. Selbst in Fällen, in denen die Objekterstellung komplex ist und mehr Speicher benötigt, möchten Sie das Objekt möglicherweise klonen und vermeiden, dass dieser komplexe Objekterstellungsprozess erstellt wird (dies hängt jedoch von Ihren Anforderungen ab). Ich denke, die Aussage "Objekterstellung ist teuer" sollte im Kontext gesehen werden.

Warten Sie in Bezug auf den JVM-Speicherbedarf auf Java 8. Sie müssen nicht einmal -Xmx angeben. Die Meta-Space-Einstellungen berücksichtigen den JVM-Speicherbedarf und werden automatisch erweitert.


Es wäre sehr konstruktiv, wenn die Leute Kommentare abgeben würden, während sie eine Antwort ablehnen. Schließlich sind wir alle hier, um Wissen zu teilen, und ein Urteil ohne richtigen Grund zu fällen, wird keinen Zweck erfüllen.
AKS

1
Der Stapelaustausch sollte über einen Mechanismus verfügen, mit dem Benutzer benachrichtigt werden, die eine Antwort abgelehnt haben, wenn ein Kommentar zu dieser Antwort veröffentlicht wird.
AKS

1

Das Erstellen einer Klasse umfasst mehr als das Zuweisen von Speicher. Es gibt auch Initialisierung, ich bin mir nicht sicher, warum dieser Teil nicht von allen Antworten abgedeckt wird. Normale Klassen enthalten einige Variablen und führen eine Art Initialisierung durch, die nicht kostenlos ist. Je nach Klasse werden möglicherweise Dateien gelesen oder andere langsame Vorgänge ausgeführt.

Überlegen Sie sich also, was der Klassenkonstruktor macht, bevor Sie herausfinden, ob er kostenlos ist oder nicht.


2
Eine gut designte Klasse sollte aus diesem Grund nicht schwer mit ihrem Konstruktor arbeiten. Beispielsweise könnte Ihre Dateileseklasse die Instanziierungskosten senken, indem sie nur überprüft, ob die Zieldatei beim Start vorhanden ist, und alle tatsächlichen Dateivorgänge bis zum ersten Methodenaufruf zurückstellt, der Daten aus der Datei benötigt.
GordonM

2
Wenn die zusätzlichen Kosten in das 'if (firstTime)' verschoben werden, ist die Neuerstellung einer Klasse in einer Schleife immer noch teurer als die Wiederverwendung der Klasse.
Alex

Ich wollte eine ähnliche Antwort posten und ich glaube, das ist die richtige Antwort. So viele Leute sind von diesen Sprüchen, dass das Erstellen von Java-Objekten billig ist, geblendet, dass sie nicht erkennen, dass Konstruktoren oder weitere Initialisierungen oft alles andere als billig sein können. Beispiel: Die ImageIcon-Klasse in Swing ist ziemlich teuer, selbst wenn Sie ein vorinstalliertes Image-Objekt übergeben. Und ich bin mit @GordonM nicht einverstanden, viele Klassen des JDK führen den größten Teil des Init im Konstruktor aus, und ich denke, dies macht den Code schlanker und besser gestaltet.
Qwertzguy

1

Javas GC ist tatsächlich sehr optimiert, um eine Vielzahl von Objekten in einem "Burst" -Verfahren schnell zu erstellen. Soweit ich verstehen kann, verwenden sie einen sequentiellen Allokator (den schnellsten und einfachsten O (1) Allokator für Anfragen variabler Größe) für diese Art von "Burst-Zyklus" in einem Speicherbereich, den sie "Eden-Raum" nennen, und nur dann, wenn die Objekte bestehen bleiben Nach einem GC-Zyklus werden sie an einen Ort gebracht, an dem der GC sie nacheinander einsammeln kann.

Wenn Ihre Leistungsanforderungen jedoch kritisch genug werden (gemessen an den tatsächlichen Anforderungen der Benutzer), sind Objekte mit einem Mehraufwand verbunden, aber ich würde bei der Erstellung / Zuweisung nicht so viel darüber nachdenken. Dies hat mehr mit der Referenzlokalität und der zusätzlichen Größe aller Objekte in Java zu tun, die für die Unterstützung von Konzepten wie Reflektion und dynamischem Versand erforderlich sind ( Floatist größer als float, bei 64-Bit mit seinen Ausrichtungsanforderungen häufig etwa viermal so groß wie) Array von Floatwird nicht unbedingt zusammenhängend von dem gespeichert, was ich verstehe).

Eines der auffälligsten Dinge, die ich je in Java gesehen habe und die mich zu einem Schwergewichts-Konkurrenten auf meinem Gebiet (VFX) gemacht haben, war ein interaktiver Multithread-Standard-Pfad-Tracer (ohne Caching der Bestrahlungsstärke oder BDPT oder MLS oder irgendetwas anderes) Die CPU liefert Echtzeitvorschauen, die relativ schnell zu einem rauschfreien Bild zusammenlaufen. Ich habe mit Profis in C ++ zusammengearbeitet, die sich mit ausgefallenen Profilern, die Schwierigkeiten damit hatten, diesen Dingen verschrieben haben.

Aber ich habe mich im Quellcode umgesehen und zwar unter Verwendung einer Vielzahl von Objekten zu geringen Kosten, aber die kritischsten Teile des Pfadverfolgers (BVH und Dreiecke und Materialien) haben Objekte sehr klar und absichtlich zugunsten großer Arrays primitiver Typen vermieden ( meistens float[]und int[]), was dazu führte, dass viel weniger Speicher verbraucht wurde und die räumliche Lokalität garantiert wurde, um von einem floatArray zum nächsten zu gelangen. Ich denke nicht, dass es zu spekulativ ist, das zu denken, wenn der Autor Boxed Types verwendet, die ihm gefallenFloatDort hätte es einen ziemlich hohen Preis für seine Leistung. Aber wir sprechen über den absolut kritischen Teil dieser Engine, und ich bin mir ziemlich sicher, dass der Entwickler diese Optimierung gemessen und sehr, sehr vernünftig angewendet hat, da er Objekte überall gerne verwendet hat Trivialkosten für seinen beeindruckenden Echtzeit-Pfadfinder.

Ein Kollege sagte mir, dass die Erstellung von Java-Objekten die teuerste Operation ist, die Sie ausführen können. Daraus kann ich nur den Schluss ziehen, so wenig Objekte wie möglich zu erstellen.

Selbst in einem so leistungskritischen Bereich wie meinem werden Sie keine effizienten Produkte schreiben, wenn Sie sich an Orten einklemmen, die keine Rolle spielen. Ich würde sogar die Behauptung aufstellen, dass die leistungskritischsten Bereiche möglicherweise eine noch höhere Nachfrage nach Produktivität aufwerfen, da wir die gesamte zusätzliche Zeit benötigen, um die Hotspots zu optimieren, die wirklich wichtig sind, indem wir keine Zeit mit Dingen verschwenden, die dies nicht tun . Wie im obigen Beispiel für den Pfadfinder hat der Autor solche Optimierungen geschickt und vernünftig nur auf die Stellen angewendet, die wirklich, wirklich von Bedeutung waren, und wahrscheinlich nach dem Vermessen im Nachhinein und immer noch überall gern verwendete Objekte.


1
Ihr erster Absatz ist auf dem richtigen Weg. Die eden und young Spaces sind Kopiensammler mit ca. 0 Kosten für tote Objekte. Ich kann diese Präsentation nur empfehlen . Nebenbei bemerkt stellen Sie fest, dass diese Frage aus dem Jahr 2012 stammt, oder?
JimmyJames

@JimmyJames Mir ist langweilig und ich möchte nur die Fragen durchgehen, auch die alten. Ich hoffe, die Leute haben nichts gegen meine Nekromantie! :-D
Dragon Energy

@JimmyJames Ist es nicht mehr so, dass Boxed Types zusätzlichen Speicherbedarf haben und nicht garantiert in einem Array zusammenhängend sind? Ich neige dazu , Objekte sind spottbillig in Java zu denken , aber das ein Fall , in dem sie relativ teuer ist wie sein könnten float[]gegenüber Float[], wo die Verarbeitung eine Million der früheren sequentiell könnte relativ ziemlich schneller als die zweiten sein.
Dragon Energy

1
Als ich anfing, hier zu posten, tat ich das auch. Wundern Sie sich nur nicht, wenn Antworten auf alte Fragen wenig Beachtung finden.
JimmyJames

1
Ich bin mir ziemlich sicher, dass Boxed Types mehr Platz benötigen als Primitive. Möglicherweise gibt es Optimierungen, aber ich denke, es ist im Allgemeinen so, wie Sie es beschreiben. Gil Tene (aus der obigen Präsentation) hat einen weiteren Vortrag über einen Vorschlag, eine spezielle Art von Sammlung hinzuzufügen, die einige der Vorteile von Strukturen bietet, aber immer noch Objekte verwendet. Es ist eine interessante Idee, ich bin mir nicht sicher, welchen Status die JSR hat. Die Kosten hängen größtenteils von der Zeit ab, auf die Sie anspielen. Wenn Sie vermeiden können, dass Ihre Objekte "entkommen", können sie sogar gestapelt werden und berühren niemals den Haufen.
JimmyJames

0

Wie die Leute bereits sagten, ist das Erstellen von Objekten in Java kein großer Aufwand (aber ich wette, es ist größer als die meisten einfachen Operationen wie Hinzufügen usw.), und Sie sollten es nicht zu sehr vermeiden.

Trotzdem sind die Kosten weiterhin hoch, und manchmal werden Sie versuchen, so viele Objekte wie möglich zu verschrotten. Aber erst nachdem die Profilerstellung gezeigt hat, dass dies ein Problem ist.

Hier ist eine großartige Präsentation zum Thema: https://www.cs.virginia.edu/kim/publicity/pldi09tutorials/memory-efficient-java-tutorial.pdf


0

Ich habe diesbezüglich ein kurzes Mikrobenchmark durchgeführt und vollständige Quellen in Github bereitgestellt. Mein Fazit ist, dass es nicht darum geht, ob das Erstellen von Objekten teuer ist oder nicht, sondern dass das kontinuierliche Erstellen von Objekten mit dem Gedanken, dass der GC die Dinge erledigt, dafür sorgt, dass Ihre Anwendung den GC-Prozess früher auslöst. GC ist ein sehr teurer Prozess, und es ist am besten, ihn zu vermeiden, wann immer es möglich ist, und nicht zu versuchen, ihn einzuschalten.


Dies scheint nichts Wesentliches über die in den vorherigen 15 Antworten gemachten und erklärten Punkte zu bieten. Kaum ein Gehalt wert eine Frage stoßen , die vor mehr als 2 Jahren gefragt wurden und hat eine bekommen sehr ausführliche Antwort
gnat
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.