Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C#] Unmanaged code; wat zit erin en hoe krijg ik het weg?

Pagina: 1
Acties:

  • Tanuki
  • Registratie: Januari 2005
  • Niet online
Mede-auteur:
  • Walance
  • Registratie: September 2005
  • Laatst online: 23-11 15:07

Walance

We hebben een webapplicatie gemaakt, met ASP.NET MVC 3.0. Deze applicatis is al een tijd in gebruik en het is ons opgevallen dat het geheugengebruik vrij hoog is. Wat ons ook opviel is dat bij het uitvoeren van verschillende acties op de website de unmanaged code groter wordt (in MB's).

Dit hebben we gemeten met ANTS Memory Profiler.

Wat we nu graag zouden willen weten is wat er nu in die unmanaged code zit. We hebben een WebDev (Cassini) proces dat nu 238 MB gebruikt, waarvan (volgens ANTS) 200 MB unmanaged code.

Hier zal ook vast wat bij zitten van Cassini en Visual Studio zelf, maar het lijkt me niet onwaarschijnlijk dat er op de een of andere manier toch unmanaged code bij zit, die niet goed opgeruimd wordt door ons.

Wat het probleem nu is: Hoe kan ik dus zien wat daar nou precies in zit? Wat ik voornamelijk wil zien is welke code daarvan door onszelf gemaakt is en dus blijkbaar niet goed wordt opgeruimd.

We hebben windbg al geprobeerd, leakdiag, ANTS.
Het moet toch wel mogelijk zijn om dit te zien?

Edit:
Ik lees op verschillende plekken dus dat het mogelijk moet zijn om te zien met windgb, maar ik kan daarna alleen voorbeelden vinden hoe ik dat van managed code kan zien. Ik zoek juist unmanaged code.

[ Voor 9% gewijzigd door Tanuki op 03-01-2013 17:28 ]

PV: Growatt MOD5000TL3-XH + 5720wp, WPB: Atlantic Explorer v4 270LC, L/L: MHI SCM 125ZM-S + SRK 50ZS-W + 2x SRK 25ZS-W + SRK 20ZS-W Modbus kWh meter nodig?


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Heb je de source-code van het native gedeelte? Goede kans dat het C++ is, dan kan je met een heap-profiler kijken (kan in sommige gevallen een rebuild met aangepaste settings vereisen), of een memory leak detector.

Probeer om te isoleren WANNEER het fout gaat, dan kan je gericht debuggen. Gebruik je wel overal waar je met IDisposable objecten werkt een using statement met de juiste scope?

Is het mogelijk dat er resources gecached worden (misschien wel door de webserver)? Zo ja, is dat dan daadwerkelijk een probleem?

-niks-


  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Allereerst, code wordt niet automagisch meer. Tenzij je het zelf schrijft. Je praat hier dus over geheugen.

Dat er unmanaged geheugen gedeclareerd gealloceerd wordt is niet meer dan normaal, de vraag is alleen of dit indirect gedeclareert wordt door jou code, of dat het door het asp.net framework gedaan wordt.

Zowiezo moet je niet Cassini gebruiken om dit soort problemen te onderzoeken, voor dit soort problemen moet je het zo realistisch mogelijk maken, m.a.w. ga het eens heel snel in IIS draaien :P

Probeer eens te achterhalen _welke_ code nu uiteindelijk ervoor zorgt dat dit geheugen gedeclareert wordt, en aangezien select is not broken zul je het uiteindelijk in je eigen code moeten zoeken..... Je gebruikt al ANTS, daarmee zou het prima moeten kunnen, en anders heeft (afhankelijk van je versie) Visual Studio ook nog ingebouwde tools.

Alleen wat is nu je probleem precies? 238 MB wordt ik niet warm of koud van namelijk...

[ Voor 7% gewijzigd door D-Raven op 04-01-2013 08:37 ]


  • Grijze Vos
  • Registratie: December 2002
  • Laatst online: 28-02 22:17
Dat is hoogst waarschijnlijk gewoon alle meuk die onder IIS hangt. Je hoeft je pas zorgen te maken als het ding maar toe blijft nemen in de loop van de tijd, en tot aan de volgende apppool recycle niet kleiner wordt.

Op zoek naar een nieuwe collega, .NET webdev, voornamelijk productontwikkeling. DM voor meer info


  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024

evolution536

besh besh

Visual studio heeft een ingebouwde performance analyzer. Overbodig grote stack sizes worden daar in ieder geval uitgehaald. Misschien kun je daar iets mee.

Ik vind je vraag wel een beetje vreemd. Unmanaged code in C# die geheugen gebruikt. Je programma gebruikt geheugen, en aangezien je een C# applicatie hebt gebruikt die wellicht veel geheugen. Onder het .NET framework zit een VM die je code draait en die tussenlaag gebruikt extra resources van je systeem. De code die je in C# schrijft wordt indirect omgezet naar MASM instructies, unmanaged code, hoe je het wel noemen. Ik denk dus dat het probleem in je C# code zit. Zo'n overbodig geheugengebruik kan al door één verkeerd (niet vernietigd of verkeerd scoped) object komen.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je bedoelt gealloceerd. Variabelen declareer je ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
.oisyn schreef op donderdag 03 januari 2013 @ 23:05:
[...]

Je bedoelt gealloceerd. Variabelen declareer je ;)
Ik declareer dat mijn geheugen gealloceerd wordt. :+

  • Tanuki
  • Registratie: Januari 2005
  • Niet online
D-Raven schreef op donderdag 03 januari 2013 @ 21:00:
Alleen wat is nu je probleem precies? 238 MB wordt ik niet warm of koud van namelijk...
Het probleem is dat de 238 MB niet meer weg gaat.

Er is dus *iets* wat nog in het geheugen blijft. Als ik profile met ANTS Memory Profiler (mooie tool, overigens), dan zie ik dat die MB's die er extra bij zijn gekomen, onder unmanaged memory vallen.

ANTS Memory Profiler heeft daar echter geen ondersteuning voor; ik kan dus niet met ANTS Memory Profiler zelf onderzoeken wat er dan precies voor objecten in zitten.

En dat is nou net hetgeen wat ik wil weten. Nu weet ik alleen dat het een zwart doosje is van (op moment van profilen) 180 MB groot.

Van de overige 238 - 180 = 58 MB geheugen weet ik wel wat er daadwerkelijk in staat, dankzij ANTS dus. Daar maak ik me ook niet zo'n zorgen om; 58 MB is nou niet heel schokkend.

Maar het unmanaged geheugen wordt alleen maar groter; het wordt niet opgeruimd. Nu is onze applicatie dermate groot dat ik ook niet in een keer kan zien waar het dan zou moeten zitten. Het zou dus helpen als ik ergens kan zien wat voor type objecten het zijn, of wat voor data erin zit (bijvoorbeeld heel grote byte arrays of iets dergelijks).

En dat is dus net de vraag die ik hier stel: Hoe kan ik zien *wat* dat stukje unmanaged geheugen nou precies bevat?

PV: Growatt MOD5000TL3-XH + 5720wp, WPB: Atlantic Explorer v4 270LC, L/L: MHI SCM 125ZM-S + SRK 50ZS-W + 2x SRK 25ZS-W + SRK 20ZS-W Modbus kWh meter nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 01:38

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ik ben niet zo thuis in .Net tools, maar wat je eventueel zou kunnen doen is gewoon simpelweg door je code heen steppen. Zoek naar een repro case die een relatief grote hoeveelheid geheugen alloceert. Plaats een breakpoint ergens in je code waarvan je zeker weet dat dat nog van voor de allocatie is. Step dan steeds over functies heen en hou in de gaten hoeveel geheugen erbij komt bij elke call. Als je op een gegeven moment een call hebt gevonden die veel geheugen alloceert, dan zou je opnieuw kunnen beginnen met een breakpoint op die call (waar je vervolgens in stept ipv eroverheen). Als je dit proces herhaalt zou je uiteindelijk bij de boosdoener terecht moeten komen.

Maar goed, er bestaan vast tools die gewoon kunnen zeggen welke code regel er verantwoordelijk is voor specifieke allocaties.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Tanuki
  • Registratie: Januari 2005
  • Niet online
.oisyn schreef op vrijdag 04 januari 2013 @ 11:16:
Ik ben niet zo thuis in .Net tools, maar wat je eventueel zou kunnen doen is gewoon simpelweg door je code heen steppen. Zoek naar een repro case die een relatief grote hoeveelheid geheugen alloceert. Plaats een breakpoint ergens in je code waarvan je zeker weet dat dat nog van voor de allocatie is. Step dan steeds over functies heen en hou in de gaten hoeveel geheugen erbij komt bij elke call. Als je op een gegeven moment een call hebt gevonden die veel geheugen alloceert, dan zou je opnieuw kunnen beginnen met een breakpoint op die call (waar je vervolgens in stept ipv eroverheen). Als je dit proces herhaalt zou je uiteindelijk bij de boosdoener terecht moeten komen.

Maar goed, er bestaan vast tools die gewoon kunnen zeggen welke code regel er verantwoordelijk is voor specifieke allocaties.
Dat bovenste had ik inderdaad al bedacht, maar wou ik eigenlijk voorkomen, omdat ik het dan zelf moet gaan zoeken. Ik verwachtte ook dat er wel tools zouden zijn die zoiets geautomatiseerd kunnen.

Blijkbaar is er weinig wat echt iets met unmanaged memory kan doen. Wel hebben we nu Memprofiler gevonden. Deze laat niet specifiek zien welke regel fout is, maar laat wel zien waar ongeveer instances uit komen die wel ge-garbage-collect worden, maar niet gedisposed worden. En nog een hele hoop andere dingen.

Daar hebben we voor nu wel iets aan; we hebben op enkele plekken in onze code al dingen rechtgezet. :)

We gaan hier nu mee verder, ik zal later nog wel even posten wat ik hier concreet nog mee opgeschoten ben, wellicht hebben andere mensen die hier naar zoeken er ook wat aan.

PV: Growatt MOD5000TL3-XH + 5720wp, WPB: Atlantic Explorer v4 270LC, L/L: MHI SCM 125ZM-S + SRK 50ZS-W + 2x SRK 25ZS-W + SRK 20ZS-W Modbus kWh meter nodig?


  • D-Raven
  • Registratie: November 2001
  • Laatst online: 16-10 10:47
Wat wellicht ook zou helpen is wat meer over de applicatie vertellen. Ben je zelf met een component aan de slag welke unmanaged geheugen alloceert???

Je zegt dat het unmanaged geheugen groeit.. hoe hard? Groet het echt de pan uit? Wordt het ook weer minder na verloop van tijd?

  • Walance
  • Registratie: September 2005
  • Laatst online: 23-11 15:07

Walance

Hm.. wat zal ik hier schrijven

Topicstarter
Ik werk samen met Tanuki bij hetzelfde bedrijf aan dit project. Het is een website waarop mensen documenten kunnen delen en beheren (dit ga ik nu niet helemaal uitleggen).

Op de website kan iemand een document publiceren, dit kan doc, docx, odt, etc zijn. De website zorgt ervoor dat dat door een bepaalde (web)service geconverteerd wordt naar pdf (dit deel doet de website dus niet zelf, dus daar komt dat geheugen niet vandaan).

Iemand kan ook gewoon een PDF uploaden. De website kijkt zoekt dan de PDF af op QR-codes. Wanneer er een wordt gevonden wordt deze in sommige situaties vervangen door een andere, of we doen dan iets specifieks met het document. Als er geen QR code wordt gevonden, of het is een geconverteerd document, dan zetten we er een nieuwe QR code op. Dit doen we allemaal met libraries van O2 Solutions en Vintasoft.

Wij moeten daarvoor PDF ook weer omzetten naar Image en Bitmap objecten. Tanuki had al gezegd dat we een deel van het probleem hadden gevonden met Memprofiler en dat was dus dit, we deden die Image en Bitmap objecten niet altijd goed opruimen.

// Edit: We gebruiken ook MEF MVVM en (een oude versie van) Griffin.MvcContrib.

[ Voor 11% gewijzigd door Walance op 04-01-2013 16:49 ]


  • Tanuki
  • Registratie: Januari 2005
  • Niet online
.

[ Voor 96% gewijzigd door Tanuki op 04-01-2013 17:42 . Reden: Flut post ]

PV: Growatt MOD5000TL3-XH + 5720wp, WPB: Atlantic Explorer v4 270LC, L/L: MHI SCM 125ZM-S + SRK 50ZS-W + 2x SRK 25ZS-W + SRK 20ZS-W Modbus kWh meter nodig?


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Het is op zich niet ongebruikelijk dat je over langere tijd een hoeveelheid gedefragmenteerd geheugen hebt, dat kan ook wat overhead opleveren. In .NET word dit al stukken minder doordat de runtime objecten kan verplaatsen in geheugen, maar dat gaat niet op voor alle stukken geheugen (ie, pinned objecten, I/O buffers etc).

Als de enige unmanaged component in je applicatie de core libraries van MS zijn, dan heb je grote kans dat je ergens zelf een bug hebt zitten met missende dispose of een reference die een object levend houd, maar eigenlijk niet meer gebruikt gaat worden. Je kan eventueel een GC forceren om de tijd, om te zien of dat helpt.

Als je het nog niet geprobeerd hebt, met de betere versies van Visual Studio krijg je volgens mij Code Analysis erbij, misschien dat die nog iets kan vinden qua fouten in gebruik-patterns.

-niks-


  • evolution536
  • Registratie: Maart 2009
  • Laatst online: 05-06-2024

evolution536

besh besh

Ik denk dat je met een debugger of disassembler aan de gang moet als je er via de managed manier niet achter kunt komen.

Waar je goed op moet letten, ook met de memoryprofiler, is de verschillen in gebruik van de stack en de heap. Als de stack dit geheugengebruik veroorzaakt klopt er duidelijk iets niet in je C# code, met de nadruk op dat je objecten niet goed worden opgeruimd. Wellicht kun je de GC extra laten lopen om te controleren of het probleem daar in zit:

C#:
1
GC.Collect();


En eventueel zou je nog wel is wat kunnen hebben aan het stackalloc keyword van C#. Hiermee kun je een object expliciet op de stack aanmaken in plaats van op de heap. Dit zorgt ervoor dat de GC niet extra draait om dit object te vernietigen en is dus qua performance ook beter. stackalloc objecten worden automatisch vernietigd zodra je uit de scope van het object springt, daar hoef je je geen zorgen om te maken.

  • R4gnax
  • Registratie: Maart 2009
  • Laatst online: 06-09 17:51
evolution536 schreef op vrijdag 04 januari 2013 @ 20:48:
En eventueel zou je nog wel is wat kunnen hebben aan het stackalloc keyword van C#. Hiermee kun je een object expliciet op de stack aanmaken in plaats van op de heap.
Daar moet echter wel de kanttekening bij geplaatst worden dat stackalloc een unsafe code context nodig heeft. Het uitvoeren van unsafe code vereist full trust permissies voor de assembly waar de unsafe code in zit. Dit zal niet altijd even handig te realiseren zijn. Zeker bij webapplicaties die ook onder lagere trust moeten draaien gaat dat moeilijk worden.

Daarnaast is de stack limiet voor de CLR maar 1 MB. In een ASP.NET omgeving is deze, als ik me goed herinner, zelfs maar 256Kb. Je wilt de stack dus nooit teveel belasten. Als je je druk maakt om de garbage collector, dan is het beter om een Pool<T> class te maken om class instances te recyclen.

[ Voor 18% gewijzigd door R4gnax op 05-01-2013 00:16 ]

Pagina: 1