För bästa minneshantering - Deklarera utanför funktion, eller innanför?

Permalänk

För bästa minneshantering - Deklarera utanför funktion, eller innanför?

Vad är bäst när det kommer till minneshantering i C?
Tänk att det handlar om mycket data nu? Flera tusen rader.
Vad skulle ni föredra?

datatyp funktion(argument){ const datatyp[rad][kolumn] = {{x,y,z}, {x,y,z}, {....}}; }

Eller

const datatyp[rad][kolumn] = {{x,y,z}, {x,y,z}, {....}}; datatyp funktion(argument){ }

Min teori är att det är bättre att ha utanför, för då är det liksom konstant i minnet. Men har man arrayen innanför, så måste minnet jobba dynamiskt för att så fort man inte anropar funktionen längre, så frigörs detta minne, dvs arrayen.

Permalänk
Medlem
Skrivet av heretic16:

Vad är bäst när det kommer till minneshantering i C?
Tänk att det handlar om mycket data nu? Flera tusen rader.
Vad skulle ni föredra?

datatyp funktion(argument){ const datatyp[rad][kolumn] = {{x,y,z}, {x,y,z}, {....}}; }

Eller

const datatyp[rad][kolumn] = {{x,y,z}, {x,y,z}, {....}}; datatyp funktion(argument){ }

Min teori är att det är bättre att ha utanför, för då är det liksom konstant i minnet. Men har man arrayen innanför, så måste minnet jobba dynamiskt för att så fort man inte anropar funktionen längre, så frigörs detta minne, dvs arrayen.

Förutsatt att datatypen inte är gigantisk (flertalet megabyte eller större) så går det snabbare att generera upp den på nytt än att läsa in den från minne. Nyttja alltid stacken i första hand - den är snabbare än andra minnen.

Skickades från m.sweclockers.com

Visa signatur

WS: MSI B350M Mortar | AMD Ryzen 7 1700 | PH-TC14PE | 32GB DDR4 3000MHz | 1TB Kingston NV2 | Intel Arc A750 8GB | 2*BenQ G2420HDB
Router: Gigabyte GA-870-UD3 | AMD Phenom II x6 1055t @ 2600MHz, 1.25V | 12GB DDR3 | 2*250GB HDD @ RAID1 | 4TB HDD
Laptop: Thinkpad X220 4291-QF6

Permalänk
Skrivet av Dracc:

Förutsatt att datatypen inte är gigantisk (flertalet megabyte eller större) så går det snabbare att generera upp den på nytt än att läsa in den från minne. Nyttja alltid stacken i första hand - den är snabbare än andra minnen.

Skickades från m.sweclockers.com

Nu har jag dålig koll på stack, men har hört talas som stack och heap. Det är väll heapen som är det "dynamiska minnet", dvs när man allokera minnet med t.ex. malloc?

Stacken i detta fall är....att man ska ha en vanlig array innuti funktionen?

Permalänk
Medlem
Skrivet av heretic16:

Nu har jag dålig koll på stack, men har hört talas som stack och heap. Det är väll heapen som är det "dynamiska minnet", dvs när man allokera minnet med t.ex. malloc?

Stacken i detta fall är....att man ska ha en vanlig array innuti funktionen?

Kort sagt så, ja. Får arrayen inte plats i stacken får du skapa upp den i heapen med malloc och sen köra free innan funktionsslut.

Skickades från m.sweclockers.com

Visa signatur

WS: MSI B350M Mortar | AMD Ryzen 7 1700 | PH-TC14PE | 32GB DDR4 3000MHz | 1TB Kingston NV2 | Intel Arc A750 8GB | 2*BenQ G2420HDB
Router: Gigabyte GA-870-UD3 | AMD Phenom II x6 1055t @ 2600MHz, 1.25V | 12GB DDR3 | 2*250GB HDD @ RAID1 | 4TB HDD
Laptop: Thinkpad X220 4291-QF6

Permalänk
Medlem

Om du har variablerna utanför, globala, så "lever" de hela tiden och tar plats.

Om du har dem inne i ett lokalt scoop, så lever variablerna och tar plats bara när scopet är aktuellt. Medan du är inne i en funktion eller innanför {} i en loop eller if-sats.

Ytterligare en fördel med lokala variabler är att du kan se till att de initieras varje gång de kommer in i scoop. Är de globala kan de ha vilket värde som helst som de fick sist de var i scoop, i den aktuella funktionen eller var som helst annars.

Ett annat problem med utanför är att det kan bli svårt att hålla reda på vilka variabler som används var. Det kan rent av spåra ut så till den milda grad att du raderar eller ändrar en funktion men glömmer att radera eller ändra de globala variablerna.

För små program spelar det ingen större roll vilket. Men större program blir snabb oöverskådliga och svåra/omöjliga att underhålla om du har många globala variabler.

En fördel med utanför är att om variablerna behöver allokeras eller initialiseras så tar det tid varje gång variablerna kommer in i scoop.

En bra kompromiss kan då ibland vara att deklarera variablerna lokalt inne, så nära platsen där de används som möjligt, men göra dem static. Då initieras/allokeras variablerna bara en gång, vid programstart och raderas inte när funktionen eller {} scopet lämnas. Men det innebär naturligtvis att de tar plats hela tiden... Om man använder sig av detta knep bör man kommentera tydligt vad man gjort och varför.

Om det gäller dynamiskt allokerade statiska variabler (pekare) så är praxis att man ger dem värdet NULL. Sedan kan man testa för det när man kommer in i funktionen första gången och då allokera minnet. Nästa gång programmet kommer in i funktionen eller innanför {} så är variabeln redan allokerad och har alltså ett annat värde än NULL.

Man bör dock vara lite försiktig. I princip innebär detta ju en form av minnesläckage.

Visa signatur

Linux och Android

Permalänk
Skrivet av Adoby:

Om du har variablerna utanför, globala, så "lever" de hela tiden och tar plats.

Om du har dem inne i ett lokalt scoop, så lever variablerna och tar plats bara när scopet är aktuellt. Medan du är inne i en funktion eller innanför {} i en loop eller if-sats.

Ytterligare en fördel med lokala variabler är att du kan se till att de initieras varje gång de kommer in i scoop. Är de globala kan de ha vilket värde som helst som de fick sist de var i scoop, i den aktuella funktionen eller var som helst annars.

Ett annat problem med utanför är att det kan bli svårt att hålla reda på vilka variabler som används var. Det kan rent av spåra ut så till den milda grad att du raderar eller ändrar en funktion men glömmer att radera eller ändra de globala variablerna.

För små program spelar det ingen större roll vilket. Men större program blir snabb oöverskådliga och svåra/omöjliga att underhålla om du har många globala variabler.

En fördel med utanför är att om variablerna behöver allokeras eller initialiseras så tar det tid varje gång variablerna kommer in i scoop.

En bra kompromiss kan då ibland vara att deklarera variablerna lokalt inne, så nära platsen där de används som möjligt, men göra dem static. Då initieras/allokeras variablerna bara en gång, vid programstart och raderas inte när funktionen eller {} scopet lämnas. Men det innebär naturligtvis att de tar plats hela tiden... Om man använder sig av detta knep bör man kommentera tydligt vad man gjort och varför.

Om det gäller dynamiskt allokerade statiska variabler (pekare) så är praxis att man ger dem värdet NULL. Sedan kan man testa för det när man kommer in i funktionen första gången och då allokera minnet. Nästa gång programmet kommer in i funktionen eller innanför {} så är variabeln redan allokerad och har alltså ett annat värde än NULL.

Man bör dock vara lite försiktig. I princip innebär detta ju en form av minnesläckage.

I detta fall kan det vara en array som har dimensionen 100*100 och är en float, dvs 4*100*100 = 40000 bytes, dvs 40 kB. Frågan är hur snabbt det går för funktionen att skapa detta minne och frigöra det? Nu talar jag inte om malloc eller calloc.

Arrayerna ska inte kunna ändras.

Permalänk
Medlem

Så länge innehållet inte skall initieras så handlar det stort sett bara om att ändra värdet på en pekare. Det går snabbt. Minnet behöver inte skapas. Det finns redan. Det behöver bara reserveras.

Om arrayerna inte skall ändras, varför vill du då skapa dem? Jag utgår från att du faktisk tänker åtminstone initiera värdena i dem på något sätt?

Om du bara behöver ha tillgång till arrayerna inne i en funktion så bör de vara lokala. Möjligen static för att slippa initiera mer än en gång, om funktionen behöver användas flera gånger.

Jag föreslår att du gör tre testprogram och jämför alla metoderna. Globalt, lokalt och lokalt static. Och ser om du kan märka/mäta någon skillnad på hastighet, om detta är väldigt viktigt.

Skickades från m.sweclockers.com

Visa signatur

Linux och Android

Permalänk
Skrivet av Adoby:

Så länge innehållet inte skall initieras så handlar det stort sett bara om att ändra värdet på en pekare. Det går snabbt. Minnet behöver inte skapas. Det finns redan. Det behöver bara reserveras.

Om arrayerna inte skall ändras, varför vill du då skapa dem? Jag utgår från att du faktisk tänker åtminstone initiera värdena i dem på något sätt?

Om du bara behöver ha tillgång till arrayerna inne i en funktion så bör de vara lokala. Möjligen static för att slippa initiera mer än en gång, om funktionen behöver användas flera gånger.

Jag föreslår att du gör tre testprogram och jämför alla metoderna. Globalt, lokalt och lokalt static. Och ser om du kan märka/mäta någon skillnad på hastighet, om detta är väldigt viktigt.

Skickades från m.sweclockers.com

Okej. Då är det nog att jag ska ha dom innuti funktionen.
Arrayerna ska vara const Men jag kan ju ha const static också.

Permalänk
Medlem

Vad tänker du ha i arrayerna och hur får du dit det, om de är const?

Skickades från m.sweclockers.com

Visa signatur

Linux och Android

Permalänk
Skrivet av Adoby:

Vad tänker du ha i arrayerna och hur får du dit det, om de är const?

Skickades från m.sweclockers.com

Det är flyttal jag tänker ha där i. Dom skapas när arrayen skapas.

Permalänk
Hedersmedlem
Skrivet av heretic16:

Det är flyttal jag tänker ha där i. Dom skapas när arrayen skapas.

Jag tolkar frågan som att eftersom du pratade om att det är en väldigt stor mängd data som ska vara i arrayen, ska du skriva in allt för hand? Eller är det inte så mycket som ska vara i?

Permalänk
Skrivet av Shimonu:

Jag tolkar frågan som att eftersom du pratade om att det är en väldigt stor mängd data som ska vara i arrayen, ska du skriva in allt för hand? Eller är det inte så mycket som ska vara i?

Arrayerna är datagenererade. Så dom ska vara endast för beräkning.

Permalänk

Strunta i tidigare inlägg i tråden. De har inte koll på vad de uttalar sig om.

Så länge din array är const spelar det ingen roll om den definieras i globalt scope eller inom funktions-scope. Oavsett var du lägger den kommer den att hamna i kod-minnet (varken på stack eller heap) och accessas på samma sätt. Eftersom den inte kan ändras kan kompilatorn lägga datat "bredvid" programkoden.

Stora mängder const-data lägger man oftast globalt, men om du bara skall använda det i en funktion kan du lägga det i funktionen också. Det spelar ingen roll. Det kommer ta lika mycket plats och accessas på samma sätt. Attributet static styr bara om symbolen skall synas utanför filen eller inte. Med static kommer du bara åt din array i samma fil. Utan static kan du ha en extern-deklaration i en headerfil och komma åt den från andra filer.

Permalänk
Skrivet av Ingetledigtnamn:

Strunta i tidigare inlägg i tråden. De har inte koll på vad de uttalar sig om.

Så länge din array är const spelar det ingen roll om den definieras i globalt scope eller inom funktions-scope. Oavsett var du lägger den kommer den att hamna i kod-minnet (varken på stack eller heap) och accessas på samma sätt. Eftersom den inte kan ändras kan kompilatorn lägga datat "bredvid" programkoden.

Stora mängder const-data lägger man oftast globalt, men om du bara skall använda det i en funktion kan du lägga det i funktionen också. Det spelar ingen roll. Det kommer ta lika mycket plats och accessas på samma sätt. Attributet static styr bara om symbolen skall synas utanför filen eller inte. Med static kommer du bara åt din array i samma fil. Utan static kan du ha en extern-deklaration i en headerfil och komma åt den från andra filer.

Tack för svaret! Då placerar jag koden innuti i funktionen

Permalänk

@heretic16: Uppenbarligen är vi flera som inte vet vad vi pratar om. Jag var lite trött i går kväll.

För en funktionslokal array (låt oss kalla den A) skall det allokeras utrymme på stacken. Är den initierad måste dessutom kompilatorn se till att dessa värden hamnar i A. Detta sker oftast genom att kompilatorn har lagt ut data (A') som A skall initeras med och kopierar A' till A. Är det är liten array kan kompilatorn även lägga ut kod som initierar den element för element.

Om, som i ditt fall, A är const skulle kompilatorn kunna strunta i att allokera den på stacken och läsa direkt från A'. Jag trodde det var en optimering som alla kompilatorer gjorde, men så är icke fallet. Om du vill vara säker på att slippa denna kopiering måste du deklarera din funktionslokala array static.

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

@heretic16: Uppenbarligen är vi flera som inte vet vad vi pratar om. Jag var lite trött i går kväll.

För en funktionslokal array (låt oss kalla den A) skall det allokeras utrymme på stacken. Är den initierad måste dessutom kompilatorn se till att dessa värden hamnar i A. Detta sker oftast genom att kompilatorn har lagt ut data (A') som A skall initeras med och kopierar A' till A. Är det är liten array kan kompilatorn även lägga ut kod som initierar den element för element.

Om, som i ditt fall, A är const skulle kompilatorn kunna strunta i att allokera den på stacken och läsa direkt från A'. Jag trodde det var en optimering som alla kompilatorer gjorde, men så är icke fallet. Om du vill vara säker på att slippa denna kopiering måste du deklarera din funktionslokala array static.

På grund av det svaga typsystemet så kan tyvärr inte så många optimeringar göras för const variabler i C/C++. Det är så vanligt att programmerare ignorerar const statusen och kastar const-pekare till nåt muterbart temporärt för de "vet vad de håller på med"...

Bloggpost om ämnet jag läste nyligen: https://theartofmachinery.com/2019/08/12/c_const_isnt_for_per...

Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Strunta i tidigare inlägg i tråden. De har inte koll på vad de uttalar sig om.

Så länge din array är const spelar det ingen roll om den definieras i globalt scope eller inom funktions-scope. Oavsett var du lägger den kommer den att hamna i kod-minnet (varken på stack eller heap) och accessas på samma sätt. Eftersom den inte kan ändras kan kompilatorn lägga datat "bredvid" programkoden.

Stora mängder const-data lägger man oftast globalt, men om du bara skall använda det i en funktion kan du lägga det i funktionen också. Det spelar ingen roll. Det kommer ta lika mycket plats och accessas på samma sätt. Attributet static styr bara om symbolen skall synas utanför filen eller inte. Med static kommer du bara åt din array i samma fil. Utan static kan du ha en extern-deklaration i en headerfil och komma åt den från andra filer.

Inte riktigt rätt....
'const' i C innebär inte att arrayen/variabeln inte kan modifieras, det bara begränsar var och när den kan modifieras. C++ har något annorlunda och striktare regler för hur 'const' fungerar.
Detta innebär att bara för att något deklareras som 'const' så styr det inte automatiskt hur en kompilator allokerar minne för det.

En array (eller annan variabel) som definieras lokalt i en funktion lever normalt (se längre ner för undantag) bara under ett funktionsanrop -. minnet för den allokeras på stacken när funktionen anropas, och frigörs när funktionen returnerar.
På många system är det inga problem att allokera stora mängder data på stacken, men för äldre system eller olika typer av inbyggda system och liknande så kan det finnas begränsningar på hur stor stacken kan bli - kod inuti en Linux kernel har t.ex. normalt bara 8KB stack tillgängligt.
Så vill man vara portabel så bör man undvika att allokera stora objekt på stacken.

Om en variabel är deklarerad som 'static' betyder dels att den inte syns utanför det kontext den deklarerades i. Så för variabler deklarerade på fil-nivå utanför någon funktion så syns namnet bara i filen i stället för att vara helt global. Variabler deklarerade lokalt i en funktion syns ändå bara inuti funktionen, så ingen ändring på den punkten.
'static' innebär dessutom att variabeln lever lika länge som programmer. För variabler på fil-nivå så är det ingen skillnad mot hur de normalt fungerar.
För variabler deklarerade lokalt i en funktion som 'static' så innebär det däremot att det bara finns en kopia av variabeln som behåller sitt värde mellan funktionsanrop, så för en lokal 'static' variabel så allokeras minne endast vid ett enda tillfälle - när programmet startas - precis som för globala variabler.

Permalänk
Skrivet av Bryal:

På grund av det svaga typsystemet så kan tyvärr inte så många optimeringar göras för const variabler i C/C++. Det är så vanligt att programmerare ignorerar const statusen och kastar const-pekare till nåt muterbart temporärt för de "vet vad de håller på med"...

Att skriva till ett const-objekt är undefined behavior och GCC utnyttjar det flitigt i andra sammanhang så jag är lite förvånad över att de inte gör det här också. Att skriva till en const array kan jämföras med att skriva till en sträng-literal (const char * som pekar till kodminnet) och man kopierar inte strängarna till skrivbart minne utifall någon skulle får för sig att skriva till dem. (Ja, det finns en option som gör det för legacy-kod.)

Permalänk
Medlem
Skrivet av Ingetledigtnamn:

Att skriva till ett const-objekt är undefined behavior och GCC utnyttjar det flitigt i andra sammanhang så jag är lite förvånad över att de inte gör det här också. Att skriva till en const array kan jämföras med att skriva till en sträng-literal (const char * som pekar till kodminnet) och man kopierar inte strängarna till skrivbart minne utifall någon skulle får för sig att skriva till dem. (Ja, det finns en option som gör det för legacy-kod.)

Jo men det är så många som gör det ändå, kanske ovetandes att det är UB. Kan tänka mig att kompilatorutvecklare avsiktligt inte utnyttjar alla fall av UB för att inte förstöra massa existerande bibliotek och system.

Visa signatur

Arbets- / Spelstation: Arch Linux - Ryzen 5 3600 - RX 7900 XT - 32G DDR4
Server: Arch Linux - Core i5-10400F - 16G DDR4

Permalänk
Medlem

Mitt tips är att du lär dig mäta tid i C och sen gör du några testrundor med stora mängder data. Då får du fakta istället för debatt, samt att du lär sig ett verktyg som är ovärderligt om du kodar saker som behöver optimeras.

Från geeksforgeeks.org:

#include <time.h>

clock_t start, end;
double cpu_time_used;

start = clock();
... /* Do the work. */
end = clock();
cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC;

Visa signatur

Processor: Motorola 68000 | Klockfrekvens: 7,09 Mhz (PAL) | Minne: 256 kB ROM / 512 kB RAM | Bussbredd: 24 bit | Joystick: Tac2 | Operativsystem: Amiga OS 1.3

Permalänk
Medlem

Har man ett program som skall vara igång länge (timmar) är det numera bäst att allokera allt minne från början även om det är fråga om tusentals megabyte. Operativsystemet swappar/pagear ut minne som eventuellt behövs av andra processer. Skall ditt program dynamiskt ständigt allokera nytt minne vid behov är risken stor att det blir fragmenterat och att det fungerar sämre eller äter upp minnet. Det är ett ständigt problem med många dåligt skrivna program. Operativsystemet är optimerat för att hantera minnet på bästa sätt, det är sällan de enskilda programmen som ofta måste startas om för att "frigöra" minne.

Permalänk
Datavetare
Skrivet av Bryal:

Jo men det är så många som gör det ändå, kanske ovetandes att det är UB. Kan tänka mig att kompilatorutvecklare avsiktligt inte utnyttjar alla fall av UB för att inte förstöra massa existerande bibliotek och system.

Kritiska här är att separera deklaration/alias från definition. I C/C++ kan man tyvärr inte göra några extra vettiga optimeringar bara för att en man har en const-pekare till något.

Orsaken är att det är helt tillåtet att skapa en const-pekare till en minnesarea som i sig inte är konstant. Alias-reglerna i C/C++ är ur den aspekten en käpp i hjulet för att kunna ge extra optimeringar.

void foo(int n); void bar(); void baz(const int *p) { foo(*p); // <- första läsning via pekare p bar(); // <- är fullt möjligt att bar() ändrar på det p pekar på :( foo(*p); // <- måste läsa om värdet från p }

Om däremot definitionen är konstant säger standarden detta:

"J.2 Undefined behavior
...
- An attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type (6.7.3)
..."

Detta är något i alla fall moderna versioner av GCC/LLVM utnyttjar. Om kompilatorn "ser" att deklarationen av data man jobbar med är konstant så läses normalt inte samma data in igen bara för att två referenser är separerade av funktionsanrop vars implementation kompilatorn inte "ser" (adress till anrop hanteras i länksteget).

Vad det gäller TS fråga kvarstår fråga: vilken typ av system handlar det om?
Är det en mikrokontroller eller på något sätt ett system mer realtidskrav allokeras data lämpligen statiskt/permanent (d.v.s. vid kompileringssteget) eller om man inte kan avgöra storleken vid det tillfället allokeras allt (och släpps aldrig) vid start så snart man vet storlek.

I fall där man av något skäl måste dynamiskt allokera och släppa minne där storleken på minnesarean varierar och är rätt hopplös att förutse så är C/C++ fel språk. Detta är ett av de fall GC med indirekt minnesreferens (t.ex. JVM och .NET/CLR) passar långt bättre då dessa är immuna mot fragmentering p.g.a. att minnet helt enkelt kan komprimeras vid behov (indirekt minnesreferens gör detta möjligt utan att "pekare" pekar fel, i C/C++ kallas dessa pekare typiskt för "handtag").

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer

Permalänk
Medlem

I överlag så är globalt state dåligt och bör undvikas i den mån det går, men i vissa fall är det oundvikligt. Därav tycker jag du bör ha datan i funktionen.

Det visar på ett bra kritiskt tänkande att du resonerar kring att datan lever dynamiskt om den är deklarerad i funktionen, men såvida du inte programmerar IoT devices med väldigt lite minne eller din data är enorm bör du inte behöva oroa dig.

Permalänk
Medlem
Skrivet av Yoshman:

I fall där man av något skäl måste dynamiskt allokera och släppa minne där storleken på minnesarean varierar och är rätt hopplös att förutse så är C/C++ fel språk. Detta är ett av de fall GC med indirekt minnesreferens (t.ex. JVM och .NET/CLR) passar långt bättre då dessa är immuna mot fragmentering p.g.a. att minnet helt enkelt kan komprimeras vid behov (indirekt minnesreferens gör detta möjligt utan att "pekare" pekar fel, i C/C++ kallas dessa pekare typiskt för "handtag").

Lite knee jerk av mig, men beroende på platform behöver man nog inte oroa sig över fragmentering i första laget. Att slänga ut manuel minneshantering pga sporadisk, dynamisk allokering känns därför lite i överkant i många fall.

Visa signatur

"Some poor, phoneless fool is probably sitting next to a waterfall somewhere, totally unaware of how angry and scared he's supposed to be." - Duncan Trussell

Permalänk
Medlem
Skrivet av Yoshman:

man av något skäl måste dynamiskt allokera och släppa minne där storleken på minnesarean varierar och är rätt hopplös att förutse så är C/C++ fel språk. Detta är ett av de fall GC med indirekt minnesreferens (t.ex. JVM och .NET/CLR) passar långt bättre då dessa är immuna mot fragmentering p.g.a. att minnet helt enkelt kan komprimeras vid behov (indirekt minnesreferens gör detta möjligt utan att "pekare" pekar fel, i C/C++ kallas dessa pekare typiskt för "handtag").

Du bör nämna, i lärandesyfte, att du inte har kontroll över när en garbage collector stoppar ditt program, hur ofta eller hur länge den körs.

Permalänk
Datavetare
Skrivet av gibbon_:

Lite knee jerk av mig, men beroende på platform behöver man nog inte oroa sig över fragmentering i första laget. Att slänga ut manuel minneshantering pga sporadisk, dynamisk allokering känns därför lite i överkant i många fall.

Helt samt, var därför jag ställde frågan kring vilket typ av system det handlar om här. Finns flera anledningar att undvika GC, men finns betydligt fler saker än att hantera eventuellt fragmentering som talar för GC.

Dels kan extern fragmentering (att man hackar upp minnet i mindre bitar) delvis undvikas genom ökad intern fragmentering (man hanterar minne i relativt få minnesblockstorlekar och avrundar storleken uppåt till närmast tillgängliga blockstorlek). Har skrivit ett par TCP/IP-stackar genom åren, där kan massor med buffertar allokeras/frias på kort tid och olika cache:ar med block i en viss storlek används både för att minimera extern fragmentering samt som prestandaoptimering.

Omvänt har GC en rad fördelar om man har flera trådar i sitt program som delvis jobbar mot delad data. Tekniker som persistent data structures kan vara väldigt effektiva här förutsatt att man har en GC och kan undvika lås samt något som kallas ABA-problemet.

Har fuskat lite inom detta, bl.a. tagit fram denna (patenterade) teknik.

Skrivet av Rolexius:

Du bör nämna, i lärandesyfte, att du inte har kontroll över när en garbage collector stoppar ditt program, hur ofta eller hur länge den körs.

Var just av sådant du nämner här jag skrev

"vilken typ av system handlar det om? Är det en mikrokontroller eller på något sätt ett system mer realtidskrav allokeras data lämpligen statiskt/permanent"

GC och hårda realtidskrav är i praktiken helt inkompatibla, däremot kan program med mjuka realtidskrav fungera med vissa typer av GC. Ett sådant exempel är GC i språket Go, där har vissa egenskaper som "compacting GC" (vilket är det som kan eliminera fragmentering helt) offrats just för att man ansåg GC vara ett krav men man kunde inte heller tulla allt för mycket på jitter.

Visa signatur

Care About Your Craft: Why spend your life developing software unless you care about doing it well? - The Pragmatic Programmer