webForumDet fria alternativet

Dynamiskt minne (jag blir galen)

C/C++ur C/C++

11 svar · 821 visningar · startad av Compusa

Medlem sedan jan. 20023 327 inlägg
Frågan#1

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". 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.

Den som kan förklara det här för mig, alternativt se vad jag gör för fel förtjänar den fetaste guldstjärnan! Just nu känns allt riktigt frustrerande.. :(

Jag har även bifogat några filer om det skulle vara till hjälp? Tre av dessa tillhör ett enkelt exempel med en länkadlista, den fjärde är testet av en dynamisk array (vilken fungerar). Var tvungen att lägga dessa i en rar-fil eftersom WF inte tillät mig att ladda upp dessa som *.cpp

Medlem sedan jan. 20023 327 inlägg
#2

Problemet ovan verkar vara relaterat till Operativsystemet. Jag gjorde dessa tester 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...

Medlem sedan juli 2002581 inlägg
#3

Du kan vara lugn. Din applikation lämnar nog tillbaka minnet om det skulle visa sig att det behövs någon annanstans.

För att kontrollera minnesläckor, använd valgrind. Det är mycket enkelt att använda. Man skriver bara:

valgrind <kommando som skall köras>

så skriver valgrind ut hur mycket minne som läcktes.

Medlem sedan jan. 20023 327 inlägg
#4

Tack Sang-drax :)
Lite lustigt att det skiljer sig såpass mellan OS, men men olika minneshantering helt enkelt. Har kört mitt program med valgrind och det gick igenom utan anmärkningar, dvs inga minnesläckage funna. Får helt enkelt kontrollera mina länkade-listor mot detta program.

Har även kört lite andra tester och det visar sig att det minnet som inte Linux avallokerar direkt återanvänds om jag skulle få för mig att lägga in 1 miljon noder ännu en gång.

Sang-drax, vad tror du det beror på att inte samma fenomen uppkommer med exempelvis en dynamisk int array? Kan det ha att göra med att detta är en primitiv typ? Hmm, när jag kör följande kod så ser jag direkt att minnet har avallokerats, även i Linux.

#include <iostream>
#include <string>

using namespace std;

void fillArray(int a[], const int& size);

int main()
{
    char var1 = 0;
    char var2 = '0';
    var1 = 66;
    cout << "var1: " << var1 << " var2: " << var2;

    char var = ' ';
    int arraySize = 0;

    cout << "Dynamic Arrays, is the shit!\n";
    cout << "Please enter the size of the array: ";
    cin >> arraySize;

    int* a = new int[arraySize];

    fillArray(a, arraySize);

    cout << "The array is filled, hit y + enter to delete!";
    cin >> var;
    delete [] a;

    cout << "Hit enter to exit!";
    cin >> var;

    return 0;
}

void fillArray(int a[], const int& size)
{
    for (int i = 0; i < size; i++)
        a[i] = i*3;
}
Medlem sedan aug. 2001145 inlägg
#5

skriv in en cout i while-loope som tar bort listan så du ser att du faktiskt går igenom alla

tänkte på en sak dock, de här head_insert(NodePtr &head, ......)

ska de vara så? NodePtr är ju Node* så känns bara konstigt att göra "Node* &head", borde väll vara att bara skicka pekaren som parameter.

void head_insert(NodePtr head, int the_number) {
}

Men som sakt, kolla så delete verkligen körs på allt.

Medlem sedan jan. 20023 327 inlägg
#6

Dies_Irae skrev:

skriv in en cout i while-loope som tar bort listan så du ser att du faktiskt går igenom alla

tänkte på en sak dock, de här head_insert(NodePtr &head, ......)

ska de vara så? NodePtr är ju Node* så känns bara konstigt att göra "Node* &head", borde väll vara att bara skicka pekaren som parameter.

void head_insert(NodePtr head, int the_number) {
}

Men som sakt, kolla så delete verkligen körs på allt.

Japp, det ska vara så, eller boken gör så i alla fall NodePtr är ju definierad som:
typedef Node* NodePtr; Gör jag så som du skriver så väcer minnesanvändingen gigantiskt, dvs pekaren till minnesadressen skrivs över. Testade precis ;)

Har kollat med cout och allt tas bort. Minnes-hanteringen fungerar det vet jag nu efter att ha gjort rigorösa test, det skumma är bara att linux envisas med att inte visa det. Tack ändå för att du tog dig tid att titta på det :)

Medlem sedan dec. 20025 483 inlägg
#7

För att se att noderna tas bort kan du lägga till en destruktor:

Node::~Node(){ static int i = 0; std::cout << ++i << std::endl; }
Medlem sedan jan. 20023 327 inlägg
#8

Japp så gör jag Peter. De filerna jag har lagt upp här är egentligen inofficiella. Först trodde jag att dessa problemen var relaterade till min implementation, så jag testade om samma fenomen inträffade i ett exempel från min kurslitteratur. Detta fenomen visade sig mycket riktigt även inträffa på det exempel. Fenomenet visade sig vara en feature i Linux ;)

Egentligen har jag följande klasser: LinkedList och Node
Det som händer nu är att man antingen kan ta bort en specifik nod, då är LinkedList ansvarig för att städa ordentligt. När hela LinkedList dör körs dess destructor och städar bort alla allokerade noder. I denna destructor har jag testat med cout. Körde nyligen valgrind på den officiella implementation och den innehöll inga minnesläckage, jippy!

Men följande fråga är fortfarande obesvarad:
I Ubuntu finns ett verktyg liknande Windows Task Manager som kallas System Monitor. Om jag har en dynamisk int array som jag allokerar med en massa element och därefter avallokerar desså så kan jag se hur applikations minnesanvänding förändras. Dvs minnesanvändingen ökar markant för att sedan återgå till hur det såg ut innan denna massiva allokering. Gör jag samma sak med mina noder så väljer Linux att allokera utrymmet, men när jag avallokerar minnet så behåller applikation detta minne ändå. Att applikationen inte läcker kan jag se genom att göra följande tre steg:
1. allokera 1 miljon noder - minnesanvänding 16 MiB
2. avllokera 1 miljon noder - minnesanvänding 16 MiB
3. allokera 1 miljon noder - minnesanvänding 16 MiB

Hoppar jag över steg 2, dvs avallokering så fördubblas minnet till ca 32 MiB.

Det känns som att detta har att göra med att Windows och Linux använder olika algoritmer för minneshanteringen. Frågan är varför den dynamiska int-arrayen inte behandlas på samma sätt.

Medlem sedan aug. 20003 575 inlägg
#9

Jag har för mig jag fick något liknande när jag gick samma utbildning,
det som jag kom fram till var att det inte var någon minnesläcka utan att programmet fortfarande hade kvar minnet till sitt förfogande. Alltså den släppte minnet till programmet men inte tillbaka till operativsystemet, testa och kör en likadan funktion efter du har kört din men släpp inte minnet. På detta sättet ser du ju om programmet återanvänder sitt minne.

/red
Ojdå läste att du kommit fram till detta i ditt senaste inlägg som jag inte riktigt orkade läsa igenom innan jag svarade :P

Medlem sedan jan. 20023 327 inlägg
#10

Nickemannen skrev:

Alltså den släppte minnet till programmet men inte tillbaka till operativsystemet

Windwos roffar åt sig minnet direkt, men inte Linux. Det verkar som att Linux resonerar som så att: "Jag ser att applikationen har allokerat minne som den inte behöver, jag väntar med att ta det i beslag eftersom jag för tillfället inte behöver det"

/Edit
Jag läser på distans denna termin ;)

Medlem sedan aug. 20003 575 inlägg
#11

Compusa skrev:

Windwos roffar åt sig minnet direkt, men inte Linux. Det verkar som att Linux resonerar som så att: "Jag ser att applikationen har allokerat minne som den inte behöver, jag väntar med att ta det i beslag eftersom jag för tillfället inte behöver det"

/Edit
Jag läser på distans denna termin ;)

Ja antagligen, och detta kanske gör att allokeringen av minne nästa gång går snäppet fortare för Linuxprogrammet.

Medlem sedan juli 2002581 inlägg
#12

Dies och Peter: går programmet igenom valgrind så är det ok. Valgrind är bättre än cout.

141 ms totalt · 3 externa anrop · v20260731065814-full.25f56b17
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
137 ms — hämta tråd, inlägg och bilagor (db)