[C#] Memory gebruik tonen

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ik gebruik in een C# programma een C++ library.
Nu is er een fix van die library wegens vermeende memory leaks in een functie die ik gebruik.

Nu kan ik natuurlijk gewoon die fix pakken en verder gaan, maar ik wil graag snappen hoe dat nu werkt met memory leaks.

Ik heb dan ook een functie ReportMemory() gemaakt die het geheugen gebruik weg schrijft in een log bestand, vervolgens roep ik de functie uit de library aan en dan nog eens ReportMemory().
Het verschil tussen de twee ReportMemory() zou dan de memory leak moeten zijn, toch?

Nu zie ik maar weinig verschil en ik vraag me dan ook af of ik het geheugen gebruik wel correct opvraag.
Dit doe ik:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    private static void ReportMemoryUse()
    {
        Process curProcess = Process.GetCurrentProcess();
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        // Create header:
        ReportMessage("PrivateMemorySize64;PeakVirtualMemorySize64;PagedSystemMemorySize64;PagedMemorySize64;NonpagedSystemMemorySize64;PeakPagedMemorySize64;VirtualMemorySize64;WorkingSet64");
        // Possible PlatformNotSupportedException
        sb.Append(curProcess.PrivateMemorySize64);
        sb.Append(";");
        sb.Append(curProcess.PeakVirtualMemorySize64);
        sb.Append(";");
        sb.Append(curProcess.PagedSystemMemorySize64);
        sb.Append(";");
        sb.Append(curProcess.PagedMemorySize64); 
        sb.Append(";");
        sb.Append(curProcess.NonpagedSystemMemorySize64); 
        sb.Append(";");
        sb.Append(curProcess.PeakPagedMemorySize64); 
        sb.Append(";");
        sb.Append(curProcess.VirtualMemorySize64);  
        sb.Append(";");
        sb.Append(curProcess.WorkingSet64); 
        ReportMessage(sb.ToString());
    }


Mijn vraag is, is er nog een manier om mogelijke memory leaks op te sporen?

Acties:
  • 0 Henk 'm!

  • GieltjE
  • Registratie: December 2003
  • Laatst online: 18-09 11:10

GieltjE

Niks te zien...

Memory profiler, je code goed nalopen en zorgen dat je alles goed disposed etc.

Echter is het goed programmeren het belangrijkste en is de GC van c# niet een van de snelste (ik heb een smerige truuc om het geheugen in te korten, maar dat is geen echte oplossing).

Hell / 0


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
GieltjE schreef op donderdag 22 oktober 2009 @ 12:10:
en is de GC van c# niet een van de snelste
Buiten het feit dat geheugen opruimen natuurlijk gewoon tijd kost, is dat nogal een bewering! Heb je daar ook bronnen van?

Verder is het niet zeker dat je de memmory leak kunt detecteren door
code:
1
2
3
ReportMemory();
LibraryCall();
ReportMemory();

Want dat is afhankelijk van wanneer de library zijn geheugen vrij zou moeten geven. Als het een managed library is, dan zou het zomaar kunnen dat het geheugen pas later bij een GC run opgeruimd word.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Ter verduidelijking:
De library is in unmanaged C++ geschreven, dan heeft de GC er toch geen invloed op?

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10-09 20:32
Yup. Unmanaged moet je zelf beheren en dus ook opruimen.
Probeer die call eens meerdere malen achter elkaar aan te roepen en dan naar het geheugen verbruik te kijken. (1k iteraties of meer).
Kan zijn dat de mem leak niet zo heel groot was. Daarnaast wordt het vrij lastig om te achterhalen WAAROM het nou optreed. Aangezien je de code van die lib niet hebt.

Acties:
  • 0 Henk 'm!

  • Laurens-R
  • Registratie: December 2002
  • Laatst online: 29-12-2024
Dan heeft de GC er inderdaad geen invloed op.

sidenote: de GC in .net 4.0 is multithreaded geimplementeerd. Niet dat magisch alle problemen daarmee als ijs voor de zon verdwijnen, maar overall gaat het er wel op vooruit.

@edit: deathraven was me net voor :)

[ Voor 8% gewijzigd door Laurens-R op 22-10-2009 12:41 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Het is een vrij langdurig proces, dus doe ik nu 3 iteraties en dan zie ik wel dat er een toename van geheugen gebruik is bij de eerste aanroep, vervolgens blijft het redelijk gelijk, maar als alles klaar is gaat het geheugen gebruik niet terug.
Ik zal van de week de fix gebruiken en dan bekijken of het beeld dan ook veranderd, ik heb er nl. een Excel grafiekje van gemaakt ;)
Het is me nu ieder geval duidelijker hoe ik het geheugen gebruik kan meten.
Ten slotte: "Meten is weten"

Acties:
  • 0 Henk 'm!

  • D-Raven
  • Registratie: November 2001
  • Laatst online: 10-09 20:32
In het vervolg is het toch een stukkie handiger om een profiler te gebruiken. Scheelt je het schrijven van een hoop van die ReportMemory() statements.

Acties:
  • 0 Henk 'm!

  • H!GHGuY
  • Registratie: December 2002
  • Niet online

H!GHGuY

Try and take over the world...

Je neemt trouwens ook niet in beschouwing dat een malloc niet altijd naar de kernel gaat om geheugen aan te vragen. En het is net die laatste die de hoeveelheid geheugen bijhoudt.

Ga je maar eens verdiepen in de glibc allocator. Die heeft bins met geheugen per size (in machten van 2) en voor grote allocaties (>=128kB voor zover ik herinner) roept hij rechtstreeks mmap aan voor een blok geheugen.
Daarnaast kun je zelfs geheugen bezet houden zonder dat het gebruikt wordt:
C++:
1
2
3
4
5
6
7
8
9
10
size_t oldmem = get_mem_info();
std::vector<void*> mem;
for (int i = 0; i < 100000; ++i)
  mem.push_back(malloc(64));
void* last = mem.back();
mem.pop_back();
for (std::vector<void*>::iterator it = mem.begin(), end = mem.end(); it != end; ++it)
  free(*it);
mem.clear();
size_t newmem = get_mem_info();

Een naieveling zou beweren dat er nog 64 byte verschil zou mogen zijn tussen oldmem en newmem (los van de vector allocatie, eventuele stack pages, en ...)
In realiteit kan het echter zijn dat er tijdens de free() geen enkele byte is teruggegeven aan het OS. De reden ligt natuurlijk aan het feit dat voor kleine allocaties sbrk() wordt gebruikt die enkel je data segment vergroot of verkleint. Je kan dus verwachten dat de laatste allocatie ook uit het einde van je data segment gehaald wordt. Aangezien die nog niet vrijgegeven is kan free() sbrk() niet aanroepen om het data segment terug te verkleinen.
Resultaat een memory "leak" van 6.4MB.

Daarnaast zijn er meestal wel nog caching effecten van de stdlib allocators en gebeurt toewijzing van geheugen aan een applicatie natuurlijk per page (typisch 4kB). Je zal dus best een paar 1000 calls doen naar die functie, wil je echt een schatting kunnen maken hoeveel de functie leakt.

[ Voor 9% gewijzigd door H!GHGuY op 22-10-2009 22:27 ]

ASSUME makes an ASS out of U and ME

Pagina: 1