Wie vergleicht sich die Speichernutzung eines in Java geschriebenen Integer-Objekts mit der Speichernutzung eines in C ++ geschriebenen Integer-Objekts? Ist der Unterschied vernachlässigbar? Kein Unterschied? Ein großer Unterschied? Ich vermute, es ist dasselbe, weil ein int ein int ist, unabhängig von der Sprache (?)
Der Grund, warum ich dies gefragt habe, ist, dass ich gelesen habe, wie wichtig es ist, zu wissen, wann der Speicherbedarf eines Programms den Programmierer daran hindert, ein bestimmtes Problem zu lösen.
Was mich fasziniert hat, ist die Menge an Speicher, die zum Erstellen eines einzelnen Java-Objekts benötigt wird. Nehmen Sie zum Beispiel ein ganzzahliges Objekt. Korrigieren Sie mich, wenn ich falsch liege, aber ein Java-Integer-Objekt 24 Byte Speicher benötigt:
- 4 Bytes für die int-Instanzvariable
- 16 Byte Overhead (Verweis auf die Klasse des Objekts, Informationen zur Speicherbereinigung und Informationen zur Synchronisierung)
- 4 Bytes Auffüllen
Als weiteres Beispiel benötigt ein Java-Array (das als Objekt implementiert ist) mehr als 48 Byte:
- 24 Byte Header-Informationen
- 16 Bytes Objekt-Overhead
- 4 Bytes für die Länge
- 4 Bytes zum Auffüllen
- plus den Speicher, der zum Speichern der Werte benötigt wird
Wie vergleichen sich diese Speichernutzungen mit demselben Code, der in C ++ geschrieben wurde?
Früher war ich mir der Speichernutzung der von mir geschriebenen C ++ - und Java-Programme nicht bewusst, aber jetzt, da ich anfange, etwas über Algorithmen zu lernen, schätze ich die Ressourcen des Computers besser.
quelle
int
? Wenn ja, sollten Sie das mitint
Java vergleichen, nichtInteger
- solange Ihre C ++ - Ints 32 Bit sind.Antworten:
Dies hängt von der Plattform und der Implementierung ab.
C ++ garantiert, dass die Größe von
char
genau einem Byte und mindestens 8 Bit breit ist. Dann ist die Größe von ashort int
mindestens 16 Bit und nicht kleiner alschar
. Die Größe von aint
ist mindestens so groß wie die Größe vonshort int
. Die Größe vonlong int
beträgt mindestens 32 Bit und ist nicht kleiner als int.sizeof(char) == 1; sizeof(long int) >= sizeof(int) >= sizeof(short int) >= sizeof(bool) >= sizeof(char).
Das eigentliche Speichermodell von C ++ ist jedoch sehr kompakt und vorhersehbar . Zum Beispiel gibt es keine Metadaten in Objekten, Arrays oder Zeigern. Strukturen und Klassen sind genau wie Arrays zusammenhängend, aber das Auffüllen kann bei Bedarf und Bedarf platziert werden.
Ehrlich gesagt ist ein solcher Vergleich bestenfalls albern, da die Java-Speichernutzung mehr von der Java-Implementierung als vom ausgeführten Code abhängt.
quelle
int32_t
.Die meisten Antworten scheinen ein paar ziemlich wichtige Punkte zu ignorieren.
Erstens sieht man in sehr viel Java praktisch nie ein Raw
int
- fast alle Verwendungszwecke sind von NutzenInteger
, so dass die Tatsache, dass einint
(ungefähr) die gleiche Größe wie einint
in C oder C ++ haben könnte, fast irrelevant ist, abgesehen davon ( Nach meiner Erfahrung ein kleiner Prozentsatz des Codes, der nurint
anstelle von verwendet wirdInteger
.Zweitens hat die Größe einzelner Objekte fast nichts mit dem Speicherbedarf eines gesamten Programms zu tun. In Java hängt der Speicherbedarf des Programms hauptsächlich davon ab, wie der Garbage Collector optimiert wurde. In den meisten Fällen wird der GC so eingestellt, dass die Geschwindigkeit maximiert wird, was (weitgehend) bedeutet, dass der GC so selten wie möglich ausgeführt wird.
Ich habe momentan keinen Link zur Hand, aber es gab einige Tests, die zeigten, dass Java mit der gleichen Geschwindigkeit wie C ausgeführt werden kann. Dazu muss der GC jedoch selten genug ausgeführt werden, damit er etwa siebenmal so viel verwendet Erinnerung. Das liegt nicht daran, dass einzelne Objekte siebenmal so groß sind, sondern daran, dass GC ziemlich teuer werden kann, wenn Sie es zu oft tun. Schlimmer noch, GC kann nur dann Speicher freigeben, wenn es "beweisen" kann, dass es keine Möglichkeit mehr gibt, auf ein Objekt zuzugreifen, und nicht nur, wenn Sie wissen, dass Sie damit fertig sind. Dies bedeutet, dass Sie, selbst wenn Sie den GC viel häufiger ausführen, um die Speichernutzung zu minimieren, wahrscheinlich immer noch ein typisches Programm mit einem größeren Speicherbedarf planen können. In einem solchen Fall können Sie den Faktor auf 2 oder 3 anstatt auf 7 reduzieren. Auch wenn Sie drastisch über Bord gehen, sollten Sie dies nicht tun.1 .
Abhängig von der Situation gibt es einen weiteren Faktor, der möglicherweise von Bedeutung ist oder nicht: den von der JVM selbst belegten Speicher. Dies ist mehr oder weniger behoben. Als Prozentsatz kann es sehr groß sein, wenn die App nicht viel eigenen Speicher benötigt, oder es kann winzig sein, wenn die App viel Speicherplatz benötigt. Zumindest auf meinem Computer scheint sogar die trivialste Java-App etwa 20 bis 25 Megabyte zu belegen (könnte für trivale Programme über 1000x oder für große Programme fast unermesslich klein sein).
1 Das heißt nicht, dass es niemandem gelingen könnte, Java mit einer Grundfläche zu schreiben, die der von C ++ entspricht. Es ist nur zu sagen , dass nur die gleiche Anzahl / Größe der Objekte aufweist und die GC läuft wirklich wird häufig nicht bekommen Sie dort in der Regel.
quelle
Integer
(warum sollten sie?) Stattint
. Nur generische Sammlungen haben keine andere Wahl, als sieInteger
aufgrund der Typlöschung zu verwenden. Wenn Sie sich jedoch darum kümmern, können Sie diese durch eine Implementierung ersetzen, die auf den vonint
Ihnen benötigten primitiven Typ spezialisiert ist . Und dann gibt es temporäres Boxen zum Durchlaufen von generischem Wrapping-Code (z. B. alles, was ein erfordertObject[]
). Haben Sie außerdem Quellen für den GC-Speicherplatz? Ich bezweifle es nicht wirklich, ich bin nur neugierig.Ich hoffe, Sie erkennen, dass all dies sowohl für Java als auch für C ++ tief in der Implementierung definiert ist. Das Objektmodell von Java benötigt jedoch viel Platz.
C ++ - Objekte benötigen (im Allgemeinen) keinen Speicher, außer dem, was die Mitglieder benötigen. Beachten Sie, dass (im Gegensatz zu Java, wo alles Benutzerdefinierte ein Referenztyp ist) der Clientcode ein Objekt sowohl als Werttyp als auch als Referenztyp verwenden kann, dh ein Objekt kann einen Zeiger / Verweis auf ein anderes Objekt speichern oder das Objekt direkt speichern ohne indirektion. Ein zusätzlicher Zeiger pro Objekt ist erforderlich, wenn es
virtual
Methoden gibt, aber einige nützliche Klassen sind so konzipiert, dass sie ohne Polymorphismus auskommen und dies nicht benötigen. Es gibt keine GC-Metadaten und keine Sperre pro Objekt. Daherclass IntWrapper { int x; public: IntWrapper(int); ... };
benötigen Objekte nicht mehr Platz als einfacheint
s und können direkt (dh ohne Indirektion) in Sammlungen und anderen Objekten platziert werden.Arrays sind einfach deshalb schwierig, weil es in C ++ kein vorgefertigtes, allgemeines Äquivalent zu einem Java-Array gibt. Sie könnten einfach eine Reihe von Objekten zuweisen
new[]
(ohne Overhead / Metadaten), aber es gibt kein Längenfeld - die Implementierung speichert wahrscheinlich eines, aber Sie können nicht darauf zugreifen.std::vector
ist ein dynamisches Array und hat daher zusätzlichen Overhead und eine größere Schnittstelle.std::array
und C-artige Arrays (int arr[N];
) benötigen eine Kompilierungszeitkonstante. Theoretisch sollte es nur der Speicher des Objekts plus eine einzelne Ganzzahl für die Länge sein. Da Sie jedoch eine dynamische Größenänderung und eine voll funktionsfähige Benutzeroberfläche mit sehr wenig zusätzlichem Speicherplatz erhalten, sollten Sie dies in der Praxis einfach tun. Beachten Sie, dass alle diese und alle anderen Sammlungen standardmäßig die Objekte nach Wert speichern, wodurch Sie Indirektion und Platz für Referenzen sparen und das Cache-Verhalten verbessern. Sie müssen explizit Zeiger speichern (bitte intelligente), um eine Indirektion zu erhalten.Die obigen Vergleiche sind nicht ganz fair, da einige dieser Einsparungen durch das Nichteinbeziehen von Funktionen erzielt werden, die Java enthält, und deren C ++ - Äquivalent häufig weniger optimiert ist als das Java-Äquivalent (*). Die übliche Art der Implementierung
virtual
in C ++ verursacht genau so viel Aufwand wie die übliche Art der Implementierungvirtual
in Java. Um eine Sperre zu erhalten, benötigen Sie ein Mutex-Objekt mit allen Funktionen, das höchstwahrscheinlich größer als einige Bits ist. Referenzzählung erhalten ( nichtEntspricht GC und sollte nicht als solches verwendet werden, ist aber manchmal nützlich. Sie benötigen einen intelligenten Zeiger, der ein Referenzzählfeld hinzufügt. Wenn das Objekt nicht sorgfältig erstellt wird, befinden sich Referenzanzahl, Smart-Pointer-Objekt und referenziertes Objekt an vollständig getrennten Positionen. Selbst wenn Sie es richtig erstellen, kann (muss?) Der gemeinsam genutzte Zeiger immer noch zwei Zeiger anstelle von einem sein. Andererseits verwendet ein guter C ++ - Stil diese Funktionen nicht genug, um eine Rolle zu spielen - in der Praxis verbrauchen die Objekte einer gut geschriebenen C ++ - Bibliothek weniger. Das bedeutet nicht unbedingt weniger Speicherauslastung insgesamt, aber es bedeutet, dass C ++ in dieser Hinsicht einen guten Vorsprung hat.(*) Sie können beispielsweise virtuelle Anrufe, Identitäts-Hash-Codes und Sperren mit nur einem Wort für einige Objekte (und zwei Wörtern für viele andere Objekte) erhalten, indem Sie die Typinformationen mit verschiedenen Flags zusammenführen und Sperrbits für Objekte entfernen Es ist unwahrscheinlich, dass Schlösser benötigt werden. Eine ausführliche Erläuterung dieser und anderer Optimierungen finden Sie unter Raum- und zeiteffiziente Implementierung des Java-Objektmodells (PDF) von David F. Bacon, Stephen J. Fink und David Grove.
quelle
Eine Ebene
int
in Java benötigt genau so viel Speicherplatz wie eineint
in C ++, vorausgesetzt, beide Implementierungen verwenden dieselbe Ganzzahlgröße und Speicherausrichtung.Ein int 'object' (eine Ganzzahl mit Box, dh eine Instanz einer Klasse
Integer
) trägt den gesamten Overhead einer Klasseninstanz in Java, ist also erheblich größer als eineint
in C ++. Wenn Sie jedoch ein Objekt in C ++ mit denselben Funktionen ausstatten, die Java-Objekte standardmäßig bieten (Polymorphismus, Boxen, Speicherbereinigung, RTTI), erhalten Sie wahrscheinlich ein gleichwertiges Objekt Größe.Und dann gibt es Optimierungsüberlegungen; Da sich die Ausführungsmodelle und Programmierparadigmen unterscheiden, ist es unwahrscheinlich, dass ein nicht triviales Problem in beiden Sprachen gleich gelöst wird. Ein Vergleich der Speichergröße auf dieser Ebene ist daher nicht sehr sinnvoll.
Ja, Java-Objekte haben standardmäßig mehr Overhead als C ++ - Klassen, aber sie verfügen über mehr Funktionen, und dies führt zu einem anderen Programmierstil - ein guter Programmierer kann die Vor- und Nachteile beider Sprachen nutzen.
quelle