sizeof(int) 4 bytes, im Taskmanager ~17 bytes
-
Hallo,
ich habe mich über den hohen Speicherverbrauchs meines Graphen gewundert, und angefangen rumzuprobieren.
Einer der Tests war eine Millionen integer zu erstellen und zu gucken was der Taskmanager dazu sagt:for (int i = 0; i < 1000000; i++) { new int(); }
ergibt im Taskmanager 17208 kb, obwohl
std::cout<<sizeof(int)<<std::endl;
4 ergibt.
Vielleicht ein paar Infos die helfen könnten: Win32, Athlon64, kompiliertes Programm 8 kb groß
Kann mir jemand erklären warum der Speicherverbrauch 4 mal so groß ist wie er sein sollte?
Zeigt der Taskmanager einfach Kappes an, wenn ja, könnt ihr mir etwas zum Speicher messen empfehlen?Vielen Dank im Voraus.
-
Halbiere doch mal die Anzahl der allokierten Integer und schau nach, wie groß das Programm dann ist. Ich prognostiziere, dass es nicht um die Hälfte schrumpft, sondern um ca. 2 MB
-
Naja, das System legt halt zu jedem allokiertem Speicher noch zusätzliche Informationen bei. Das dies bei kleinen Objekten meistens ein vielfaches ihrer eigenen Grösse ist, ist durchaus bekannt. Deshalb verwendet man in solchen Fällen oft auch eine eigene Speicherverwaltung. Man allokiert grössere Mengen an Speicher im voraus und verteilt diese dann selber.
So ein Verfahren wird zum Beispiel in Modern C++ Design erklärt. Gibt aber sicher noch bessere Bücher für dieses Themengebiet, da man dazu eigentlich ein eigenes Buch schreiben könnte
Damit du es mal selber siehst, mach sowas:
#include <iostream> #include <algorithm> int main() { int* field = new int[1000000]; std::fill_n(field, 1000000, 9); std::cin.get(); delete[] field; return 0; }
Du wirst bemerken, dass der Speicherverbrauch deutlich gesunken ist, obwohl genau gleichviele
int
Objekte angelegt wurden.Grüssli
-
Tatsache, 5452 kb laut Taskmanager.
Vielen Dank, komme von Python und Java, daher ist mir Speicherverwaltung noch neu.
Ich werde zusehen, dass ich mir etwas über Memory Allocation anlese. boost pool scheint sich da anzubieten, wenn ich das richtig sehe.
-
muuh schrieb:
Ich werde zusehen, dass ich mir etwas über Memory Allocation anlese. boost pool scheint sich da anzubieten, wenn ich das richtig sehe.
Meistens ist std::vector, std::list, etc der perfekte Pool
-
Naja, was ich zur Zeit mache ist:
std::list<Node*> nodes;
Node* Graph::addNode(int x, int y, int z) { Node* node = new Node(x, y, z); nodes.push_back(node); return node; }
Aber da ich Probleme mit dem Speicher bekomme scheints falsch zu sein.
-
Gibst du den Speicher wieder frei? Und wieso nimmst du keine
std::list<Node>
?Brauchst du die Zeiger? Falls ja, bieten sich Smart Pointer und Pointer Container aus Boost an...
-
Ja ich gebe den Speicher wieder frei, aber wenn ich mich nicht irre wärs auch egal wenn nicht, denn zur Zeit lass ichs nur einmal durchlaufen.
Die Zeiger brauche ich, Smart Pointer und Pointer Container gucke ich mir mal an.
Ich habe keine std::list<Node> benutzt, weil ich mir nicht sicher war, ob so etwas richtig ist:
std::list<Node> nodes;
Node* Graph::addNode(int x, int y, int z) { nodes.push_back(*(new Node(x, y, z)); return &(nodes.back()); }
Ich habe das Gefühl das ist nicht so gut...
-
muuh schrieb:
Ja ich gebe den Speicher wieder frei, aber wenn ich mich nicht irre wärs auch egal wenn nicht, denn zur Zeit lass ichs nur einmal durchlaufen.
Du irrst dich! Zu jedem
new
kommt eindelete
und zu jedemnew[]
kommt eindelete[]
. Du kannst dich nicht darauf verlassen, dass irgendjemand anderes deinen Speicher freigibt.muuh schrieb:
Die Zeiger brauche ich, ...
Keine sinnvolle Antwort.
muuh schrieb:
Ich habe keine std::list<Node> benutzt, weil ich mir nicht sicher war, ob so etwas richtig ist:
...
Ich habe das Gefühl das ist nicht so gut...
omg
Das ist wirklich nicht gut, aber zeigt schön deine Herkunft auf. In C++ muss man nicht jedes Objekt mit new anlegen. Dies ist nur nötig, wenn man es auf dem Heap haben will und die Speicherverwaltung übernimmt. Das folgende wäre vielleicht eher was du suchst:std::list<Node> nodes; // ... Node& Graph::addNode(int x, int y, int z) { nodes.push_back(Node(x, y, z)); return nodes.back(); }
Ganz ehrlich, wenn du dich in Python oder Java auskennst, dann solltest du trotzdem ein C++ Buch kaufen. Die Sprachen sind VIEL ZU VERSCHIEDEN. Es ist ein Fehlschluss, wenn du meinst, dass du mit deinem Java Wissen auch C++ programmieren kannst. Das führt zu nichts!
Empfohlene Bücher:
- C++ Primer
- Thinking in C++ 1&2
- Die C++ ProgrammierspracheGrüssli
-
Naja, ich habe gelesen, dass der Heap viel größer ist als der Stack, und da ich vor habe über eine Millionen Knoten anzulegen, zu jedem Knoten mehrere Kanten anzulegen und dann zu durchsuchen... Nunja, ich dachte da sei es eine bessere Idee das auf den Heap zu packen.
Ich werde mich mal um ein wenig Bücher zu c++ bemühen.
Danke.
-
muuh schrieb:
Naja, ich habe gelesen, dass der Heap viel größer ist als der Stack, und da ich vor habe über eine Millionen Knoten anzulegen, zu jedem Knoten mehrere Kanten anzulegen und dann zu durchsuchen... Nunja, ich dachte da sei es eine bessere Idee das auf den Heap zu packen.
Die Sache ist aber, dass
std::list
einen Defaultallokator intern benutzt. Dasstd::list
Objekt bleibt immer gleich gross, egal wieviele Objekte du reinstopfst, dennstd::list
setzt diese intern über den Defaultallokator auf den Heap. Aber sowas lernt man in einem guten C++ BuchGrüssli
-
muuh schrieb:
Naja, ich habe gelesen, dass der Heap viel größer ist als der Stack, und da ich vor habe über eine Millionen Knoten anzulegen, zu jedem Knoten mehrere Kanten anzulegen und dann zu durchsuchen... Nunja, ich dachte da sei es eine bessere Idee das auf den Heap zu packen.
std::list
und die anderen STL-Container verwenden alle intern den Heap, du bekommst davon einfach nichts mit und hast dich nicht ums Freigeben zu kümmern.Aber ich kann Dravere nur zustimmen: Die Konzepte von C++ sind in vieler Hinsicht sehr speziell. Ein Neu-Lernen bringt mehr als ein Umlernen, denn die Gemeinsamkeiten hören schon bald einmal auf...
-
muuh schrieb:
Naja, ich habe gelesen, dass der Heap viel größer ist als der Stack, und da ich vor habe über eine Millionen Knoten anzulegen, zu jedem Knoten mehrere Kanten anzulegen und dann zu durchsuchen... Nunja, ich dachte da sei es eine bessere Idee das auf den Heap zu packen.
Wenn du sowas schreibst:
myList.push_back(Node(x,y,z));
passiert folgendes:
1. ein Node-Objekt wird auf dem Stack angelegt.
2. die Memberfunktion push_back wird auf myList aufgerufen, ihr wird dieses Node-Objekt per Referenz übergeben
3. push_back erzeugt einen Listenknoten auf dem Heap und kopiert das übergebene Node-Objekt dort rein
4. das in Schritt 1 erzeugte Node-Objekt wird, da es ein temporäres Objekt ist, am Ende des Statements zerstört (sonst bei Verlassen des Scopes)es existiert jetzt nur noch ein Node als Teil eines Listenknotens auf dem Heap.
-
Advanced C++ hat nen schönes Beispiel mit Erklärung für einen Small-Object-Allocator.
-
Ah, das ist cool, danke für eure Hilfe.
-
Eine Frage hätte ich doch noch:
Test 1:
Eine Millionen Knoten in einen vector speichern.
Knoten haben 6 integer (24 byte).
Speicherverbrauch ~25 mb.Test 2:
Eine Millionen Knoten in einen vector speichern.
Knoten haben einen vector (24 byte).
Speicherverbrauch ~41 mb.Woran liegt das?
-
Sehrwahrscheinlich liegt es daran, dass der
std::vector
ein wenig Speicher auf Vorrat allokiert, um besseres Laufzeitverhalten zu erzeugen. Bei vielen kleinen Containern macht das etwas aus.Um mehr zu sagen, müsstest du uns den Code zeigen und sagen, wieviel bei dir
sizeof
des jeweiligen Elementtypen ausgibt. Eventuell spielt Alignment auch noch eine Rolle.
-
Test 1:
class Node { private: int a; int b; int c; int d; int e; int f; public: Node(); ~ Node(); };
Node:: Node() { } Node::~ Node() { }
int main(int agc, char* argv[]) { std::vector< Node > field; for (int i = 0; i < 1000000; i++) { field.push_back(Node()); } std::cout<<sizeof(Node)<<std::endl; std::cout<<sizeof(int)<<std::endl; std::cin.get(); return 0; }
Die Ausgabe ist:
24
4taskmanager: 25192 kb
Und Test 2:
class Node { private: std::vector<int> myVec; public: Node(); ~ Node(); };
Node:: Node() { } Node::~ Node() { }
int main(int agc, char* argv[]) { std::vector< Node > field; for (int i = 0; i < 1000000; i++) { field.push_back(Knoten()); } std::cout<<sizeof(Node)<<std::endl; std::cout<<sizeof(std::vector<int>)<<std::endl; std::cin.get(); return 0; }
Die Ausgabe ist:
24
24Taskmanager: 40856 kb
-
Was denkst Du mit sizeof(std::vector<int>) zu messen?
Simon
-
Den Speicher den myVec belegt.
myVec.capacity() ist übrigens 0.