Skip to content

Innlegg

Typer søppelinnsamling i .Net Core

2. september 2019 • 4 min lesing

Typer søppelinnsamling i .Net Core

Minnehåndtering i moderne språk er ofte en ettertanke. For alle praktiske formål skriver vi programvare uten å tenke på minne. Dette tjener oss godt, men det finnes alltid unntak…

I California er det omfattende krav til finansiell rapportering for Local Education Agencies (LEA), en LEA kan være et fylke, et distrikt, en charter eller en enkelt skole. De fleste LEAer lager sine egne finansielle rapporter som vanligvis er sentrert rundt Excel, det er ikke overraskende når hver rapport er forskjellig. For å løse dette problemet bestilte California Board of Education programvare for å generere finansielle rapporter.

Jeg var en del av utviklingsteamet.

Mitt første stopp var testloggene, Ed-Pros logger pekte på høy minnebruk, kanskje det var en minnelekkasje? En ingeniør observerte at Ed-Pros beregninger brukte store mengder kortvarig minne. Hvis minnet ikke ble ryddet opp raskt, kunne det se ut som en minnelekkasje.

Ed-Pro er bygget på toppen av .Net Core, Microsofts multiplattformrammeverk. I .Net Core er minnet delt inn i tre kategorier: Kortvarig (Gen0), mellomvarig (Gen1), og langvarig (Gen2). Gen0 er for kortvarige data som raskt går ut av omfang, Gen1 er for mellomvarig minne som henger rundt litt lenger, det går også til slutt ut av omfang og Gen2 er langvarig minne som kan leve for hele applikasjonens levetid. Gen0-minne blir konstant gjenvunnet, Gen1 blir gjenvunnet mindre hyppig enn Gen0, og Gen2 blir gjenvunnet enda mindre hyppig enn Gen1.

Den eneste sikre måten å forstå minnebruken til Ed-Pro var å profilere den, nedenfor er et skjermbilde som bruker dotMemory av JetBrains.

Som mistenkt fant vi store mengder Gen0-minne (det blå), så mye at det så ut som søppelinnsamling ikke kunne følge med. En strategi for å kompensere for store mengder minne, forårsaket at søppelinnsamling oscillerte mellom å øke minneplass (legge til mer minne for applikasjonens bruk) og rydde det opp. Under oppryddingssyklusene er applikasjonen ikke responsiv.

Først var vi forvirret, er ikke formålet med GC å holde minnet ryddig? To artikler var instrumentelle i vår forståelse av hvordan søppelinnsamling fungerer i .Net: Mark Vincze’s artikkel Troubleshooting high memory usage with ASP.Net Core on Kubernetes og Fundamentals of Garbage Collection av Microsoft. Begge er flotte lesninger og brakte klarhet til minnebruken i Ed-Pro.

Her er et sammendrag av det vi lærte, det finnes to typer søppelinnsamling i .Net: Server søppelinnsamling og Workstation søppelinnsamling.

Server søppelinnsamling gjør et par antagelser: Først, det er rikelig med minne tilgjengelig og for det andre, prosessorene er flerkjerne og er raske. Begge kan være sanne, men vi lever i en verden av virtuelle maskiner og Docker hvor det er mer sannsynlig at begge antagelser er falske.

Server søppelinnsamling lar minnet bygge seg opp, på et tidspunkt gjør den en av to ting: den enten øker minneplassen som lar minnet vokse eller den frigjør foreldreløst minne. Når den velger å frigjøre minne, starter søppelinnsamlingen prosessen på en høy prioritetstråd. Den høye prioritetstråden har høyere prioritet enn applikasjonen; hvis maskinen er rask, bør ikke oppryddingen merkes. Men hvis den ikke er det, vil det få applikasjonen til å stoppe til oppryddingen er fullført.

Workstation søppelinnsamling opererer annerledes. Den kjører kontinuerlig og gjenvinner minne på en tråd med samme prioritet som applikasjonen. Dette betyr at den også konkurrerer om ressurser med applikasjonen som kan forårsake applikasjonslanghet. Oppsiden er at applikasjonens minnebruk kan holde seg ganske lav, primært når den bruker store mengder Gen0.

Som standard, hvis .Net Core oppdager en server, kjører den Server søppelinnsamlingstypen, som var tilfellet med vår applikasjon. For å kjøre Workstation søppelinnsamlingstypen legg til følgende utdrag i prosjektfilen din:

  <PropertyGroup> 
    <ServerGarbageCollection>false</ServerGarbageCollection>
  </PropertyGroup>

Vi gjorde denne konfigurasjonsendringen til Ed-Pro, ved å bruke dotMemory profilert vi Ed-Pros minne med Workstation søppelinnsamling aktivert og lastet de samme skjermene som i den forrige testen. Her er resultatene:

Minnebruken er betydelig redusert. Gen0-allokeringene er praktisk talt ikke-eksisterende. Utover forskjellene i grafen, toppet Server søppelinnsamlingens minnebruk på 1 gig mens Workstation søppelinnsamlingen toppet på omtrent 200 meg.

Hver applikasjon er forskjellig. Vår applikasjon brukte en masse midlertidige data og bruker dermed en masse Gen0-minne. Din applikasjon kan utnytte lengre levd minne som Gen1 eller Gen2 hvor Server søppelinnsamling gir mye mening. Mitt råd er å profilere minnet ditt under forskjellige forhold for å få en ide om hvordan minne brukes og deretter bestemme hvilken modus som er best for din applikasjon.

Forfatter: Chuck Conway spesialiserer seg på programvareutvikling og Generativ AI. Koble til ham på sosiale medier: X (@chuckconway) eller besøk ham på YouTube.

↑ Tilbake til toppen

Du liker kanskje også