Innlegg
Søppelsamlingstyper i .Net Core
2. september 2019 • 4 min lesing
Minnehåndtering i moderne språk er ofte en ettertanke. For all praktisk talt, skriver vi programvare uten å tenke på minne. Dette tjener oss godt, men det er alltid unntak…
I California er det omfattende krav til finansiell rapportering for lokale utdanningsbyråer (LEA). En LEA kan være et fylke, et distrikt, en charter eller en enkelt skole. De fleste LEA-er lager sine egne finansielle rapporter som vanligvis er sentrert rundt Excel, så det er ikke overraskende når hver rapport er forskjellig. For å løse dette problemet ga California Board of Education i oppdrag programvare for å generere finansielle rapporter.
Jeg var en del av utviklingsteamet.
Mitt første stoppested var testingsloggene. Ed-Pro sine logger pekte på høyt minnebruk, kanskje det var en minnelekk? En ingeniør observerte at Ed-Pro sine beregninger brukte en stor mengde kortvarig minne. Hvis minnet ikke ble ryddet opp raskt, kunne det se ut som en minnelekk.
Ed-Pro er bygget på toppen av .Net Core, Microsofts multi-plattform rammeverk. I .Net Core er minnet delt inn i tre kategorier: Kortvarig (Gen0), medium varig (Gen1), og langvarig (Gen2). Gen0 er for kortvarig data som raskt går ut av omfang, Gen1 er for medium varig minne som henger rundt litt lenger, det går også til slutt ut av omfang, og Gen2 er langvarig minne som kan leve i 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 ved bruk av dotMemory av JetBrains.
Som forventet fant vi store mengder Gen0-minne (det blå), så mye at det så ut til at søppelsamlingen ikke kunne holde tritt. En strategi for å kompensere for en stor mengde minne førte til at søppelsamlingen oscillerte mellom å øke minneplassen (legge til mer minne for applikasjonens bruk) og å rydde den opp. Under oppryddingssyklene er applikasjonen ikke responsiv.
Til å begynne med var vi forvirret. Er ikke formålet med GC å holde minnet ryddig? To artikler var instrumentelle i vår forståelse av hvordan søppelsamling fungerer i .Net: Mark Vinczes artikkel Troubleshooting high memory usage with ASP.Net Core on Kubernetes og Fundamentals of Garbage Collection av Microsoft. Begge er flotte lesninger og ga klarhet til minnebruken i Ed-Pro.
Her er et sammendrag av det vi lærte. Det finnes to typer søppelsamling i .Net: Server Garbage Collection og Workstation Garbage Collection.
Server Garbage Collection gjør et par antakelser: For det første er det rikelig med minne tilgjengelig, og for det andre er prosessorene multi-kjerne og raske. Begge kan være sanne, men vi lever i en verden av virtuelle maskiner og Docker der det er mer sannsynlig at begge antakelsene er usanne.
Server Garbage Collection tillater minne å bygges opp. På et tidspunkt gjør det en av to ting: det øker enten minneplassen slik at minnet kan vokse, eller det frigjør foreldreløst minne. Når det velger å frigjøre minne, starter søppelsamlingen prosessen på en høy prioritetstråd. Høy prioritetstråden har høyere prioritet enn applikasjonen. Hvis maskinen er rask, bør oppryddingen ikke merkes. Men hvis den ikke er det, vil det få applikasjonen til å stoppe opp til oppryddingen er fullført.
Workstation Garbage Collection fungerer annerledes. Det kjører kontinuerlig og gjenvinner minne på en tråd med samme prioritet som applikasjonen. Dette betyr at det også konkurrerer om ressurser med applikasjonen, noe som kan forårsake applikasjonssakthet. Fordelen er at applikasjonens minnebruk kan holdes ganske lav, primært når den bruker store mengder Gen0.
Som standard, hvis .Net Core oppdager en server, kjører det Server Garbage Collection-typen, som var tilfellet med vår applikasjon. For å kjøre Workstation Garbage Collection-typen, legg til følgende utdrag i prosjektfilen din:
<PropertyGroup>
<ServerGarbageCollection>false</ServerGarbageCollection>
</PropertyGroup>
Vi gjorde denne konfigurasjonsendringen til Ed-Pro. Ved bruk av dotMemory profilerede vi Ed-Pros minne med Workstation Garbage Collection aktivert og lastet de samme skjermene som i forrige test. Her er resultatene:
Minnebruken er betydelig redusert. Gen0-allokeringene er praktisk talt ikke-eksistente. Utover forskjellene i grafen, toppet Server Garbage Collection minnebruken 1 gig, mens Workstation Garbage Collection toppet på omtrent 200 megs.
Hver applikasjon er forskjellig. Vår applikasjon brukte mye midlertidig data og bruker dermed mye Gen0-minne. Din applikasjon kan utnytte lengre levd minne som Gen1 eller Gen2, der Server Garbage Collection gir mye mening. Min råd er å profilere minnet ditt under forskjellige forhold for å få en ide om hvordan minnet brukes, og deretter bestemme hvilken modus som er best for applikasjonen din.
Forfatter: Chuck Conway er en AI-ingeniør med nesten 30 års erfaring innen programvareutvikling. Han bygger praktiske AI-systemer—innholdspipelines, infrastrukturagenter og verktøy som løser virkelige problemer—og deler det han lærer underveis. Koble til ham på sosiale medier: X (@chuckconway) eller besøk ham på YouTube og på SubStack.