C++, problem med dynamiskt minne

Permalänk
Medlem

C++, problem med dynamiskt minne

Hej!
Håller på att implementera en länkad lista, bland annat för att lära mig hantera pekare och dynamiskt minne mm.

För varje ny nod som skapas i listan så allokerar jag minne för denna med hjälp av new. För att se hur mycket minne min applikation använder så tittar jag på "Mem usage" i ett system-verktyg liknande "Windows Task Manager" fast för Ubuntu. Jag har gjort att lite test-program för min länkade lista där jag kan bestämma hur många noder jag ska skapa. Om jag exempelvis väljer att skapa en miljon noder så ser jag direkt att minnesanvändingen för min applikation ökar från ca 800 KB till 16 mb. Allt väl så långt. Om jag väljer att ta bort alla noder och köra delete på var och en av dessa så upptar min applikation fortfarande lika mycket minne dvs 16 mb! Varför?

Om jag gör något liknande fast med en dynamisk array så blir det inte så här. Jag tänkte att det kanske var jag som implementerat det hela konstigt så jag valde att skriva av ett exempel på en länkad lista från min bok men det gjorde ingen skillnad alls.

Problemet ovan verkar vara relaterat till Operativsystemet. Jag gjorde testerna som jag beskrev ovan i Ubuntu (Linux dist). Testar jag samma program i Windows så lämnar min applikation nästan tillbaks allt minne. Min fråga är då varför det är så här? Om jag kör delete så är det ju för att jag inte längre behöver använda minnet...

Så här såg det ut innan jag allokerade minne i Windows:
Memory used: 960 k

Efter att jag allokerat minne för 1 miljon noder:
Memory used: 16652 k

Efter att jag tagit bort allt allokerat minne för noderna:
Memory used: 1108 k

Känns ju som ett litet minnesläckage? Blir inte mycket klokare, snarare mer förtvivlad...

Nedan följer den förenklade versionen av mitt program med en länkad lista..

Node.h

#ifndef NODE_H #define NODE_H namespace linkedlistofclasses { class Node { public: Node( ); Node(int value, Node *next); int getData( ) const; Node *getLink( ) const; void setData(int value); void setLink(Node *next); private: int data; Node *link; }; typedef Node* NodePtr; } #endif // NODE_H

Node.cpp

#include <iostream> #include "Node.h" namespace linkedlistofclasses { Node::Node( ) : data(0), link(NULL) { // } Node::Node(int value, Node *next) : data(value), link(next) { // } int Node::getData( ) const { return data; } Node* Node::getLink( ) const { return link; } void Node::setData(int value) { data = value; } void Node::setLink(Node *next) { link = next; } }

main.cpp (test program)

#include <iostream> #include "Node.h" using namespace std; using namespace linkedlistofclasses; void head_insert(NodePtr &head, int the_number) { NodePtr temp_ptr; temp_ptr = new Node(the_number, head); head = temp_ptr; } int main() { NodePtr head, temp = NULL; int size = 0; char input = ' '; head = new Node(0, NULL); cout << "Please enter number of elements: "; cin >> size; for (int i = 0; i < size; i++) { head_insert(head, i); } cout << "Delete the nodes? "; cin >> input; temp = head; while (temp != NULL) { NodePtr nodeToDelete = temp; temp = temp->getLink(); delete nodeToDelete; nodeToDelete = NULL; } cout << "Nodes deleted..."; cin >> input; return 0; }

Permalänk

Jag har för mig att linux som operativsystem inte avallokerar minne mer än nödvändigt, så det kan vara orsaken.
Men jag kan inte se vad NodePtr är för något. Hade det stått Node* så borde det funka som du tycker (med undantag för eventuella linuxegenheter)...

Permalänk

typedef Node* NodePtr;

Permalänk
Medlem

Det du säger om linux, verkar tyvärr stämma, i alla fall om jag ser till hur mitt program uppträder där

Men är det då inte skumt att linux avallokerar en dynamisk array direkt?

Jag har försökt söka runt på Google, för att se om detta diskuterats av andra men hittills har jag inte hitta mycket som varit värt att läsa. Känns som det bara är jag som reagerat över detta.

Permalänk
Medlem

för att kolla minnesläckor så kan jag rekomendera valgrind

Visa signatur

weeeee

Permalänk
Medlem

Tack för tipset! Körde mitt program valgrind och programet innehöll inga minnesläckor. Fortfarande lite irreterande att man inte kan se när programet avallokerar minnet dock. Hmm, kanske bara att acceptera, även om det är svårt

Permalänk

Testa kör 1000 iterationer och kolla om det är mera minne som inte är frigjort.

Permalänk
Medlem

alexandersson: vet ej om jag förstod dig rätt, men jag gjorde två test som fick mig att bli lite "klokare".

Test 1:
Steg 1: Allokera plats för 1 miljon noder
Steg 2: Avallokera alla dessa platser
Steg 3: Allokera plats för 1 miljon nya noder

Resultat test 1:
Vid uppstart tar programet 836.0 Kib
Efter steg 1: 16.1 MiB
Efter steg 2: 16.1 MiB
Efter steg 3: 16.1 MiB

Kontenta: Linux väljer alltså att inte avallokera minnet för min applikation om det inte behövs, utan behåller det ifall jag skulle behöva använda det igen?

Test 2:
Jag gjorde även detta test, för att se vad som händer om jag inte avallokerar minnet innan jag lägger till 1 miljon noder ännu en gång...

Steg 1: Allokera plats för 1 miljon noder
Steg 2: Allokera plats för 1 miljon nya noder

Resultat test 1:
Vid uppstart tar programet 836.0 Kib
Efter steg 1: 16.1 MiB
Efter steg 2: 31.3 MiB

Intressant

Permalänk
Inaktiv

I Windows så vill du titta på VM Size (View->Select Columns för att få fram det). Det borde finnas någon motsvarighet i ubuntu.

Permalänk

hur jag menar.

showmemory do 1000000 times { allocatenode } cleanup // Jämför denna... showmemory do 1000 times { do 1000000 times { allocatenode } cleanup } // Med denna... showmemory

Permalänk
Medlem

Troligen så avallokerar OSet minnet när den tycker det är "lämpligt" och detta kanske läggs i en lista som sedan avallokeras som ett helt gäng. Kan tänka mig att det är ungefär som när man formaterar en disk, själva FATen är nollad men minnet är inte frigjort utan de görs sedan om det verkligen behövs.

Permalänk
Medlem

Nu har jag kört ett test enligt dina specifikationer:

Och minnes-värdena för virtuellt och resisten minne var identiska efter båda testerna:

Virtuellt minne
17.8 MiB

Residental Memory
16.1 MiB

Med andra ord så sparar Linux det avallokerade minnet tillsvidare för att kunna återanvända det om det skulle behövas.

Permalänk

Du skulle kunna lägga in ett test som mäter tiden det tar att allokera i de olika situationer. Och om du orkar skulle du även kunna testa i Windows som jämförelse

Permalänk
Medlem

Absolut, behöver bara lite tid

Är det ingen annan här som tänkt på detta när han/hon programmerat med C++?