Spørsmål:
Jeg bruker for mye RAM. Hvordan kan dette måles?
Madivad
2014-03-16 20:00:54 UTC
view on stackexchange narkive permalink

Jeg vil gjerne vite hvor mye RAM jeg bruker i prosjektet mitt, så vidt jeg kan vite, er det ingen måte å faktisk finne ut av det (annet enn å gå gjennom og beregne det selv). Jeg har kommet til et stadium i et ganske stort prosjekt der jeg har bestemt at jeg går tom for RAM.

Jeg har bestemt dette fordi jeg kan legge til en seksjon, og så bryter alt helvete løs et annet sted i koden min uten noen åpenbar grunn. Hvis jeg #ifndef noe annet ute, fungerer det igjen. Det er ikke noe programmatisk galt med den nye koden.

Jeg mistenkte en stund at jeg kom til slutten av tilgjengelig RAM. Jeg tror ikke jeg bruker for mye stack (selv om det er mulig). Hva er den beste måten å bestemme hvor mye RAM jeg faktisk bruker?

Jeg går gjennom og prøver å finne ut har problemer når jeg kommer til enums og strukturer; hvor mye minne koster de?

første redigering: OGSÅ, jeg har redigert skissen min så mye siden starten, dette er ikke de faktiske resultatene jeg opprinnelig fikk, men det er det jeg får nå.

  tekstdata bss des hex filnavn 17554844449 18847 499f HA15_20140317w.cpp.elf 16316 694 409 17419 440b HA15_20140317w.cpp.elf 17346790426 18562 4882 HA15_20140317w.cpp.elf  

Den første linjen (med tekst 17554) virket ikke, etter mye redigering fungerer den andre linjen (med tekst 16316) som den skal.

rediger: den tredje linjen har alt som fungerer, seriell lesing, mine nye funksjoner osv. Jeg fjernet egentlig noen globale variabler og dupliserte koder. Jeg nevner dette fordi (som mistenkt) det ikke handler om denne koden per sae, det må handle om RAM-bruk. Som bringer meg tilbake til det opprinnelige spørsmålet, "hvordan måler jeg det best" Jeg sjekker fremdeles noen svar, takk.

Hvordan tolker jeg egentlig informasjonen ovenfor?

Så langt er min forståelse:

  `TEXT 'er programinstruksjonsminne
`DATA` er variabler (enhetliggjort?) I programminnet` BSS` er variabler som opptar RAM  

siden BSS er betydelig mindre enn 1024 byte, hvorfor fungerer den andre, men den første virker ikke ' t? Hvis det er DATA + BSS , opptar begge mer enn 1024. nå har jeg fjernet det fordi det egentlig ikke hadde noe å gjøre med problemet (annet enn kanskje dårlig kodingspraksis, variabel erklæring og lignende). Du kan se gjennom koden ved å se tilbake gjennom endringene hvis du virkelig vil se den. Jeg ønsket å komme tilbake til det aktuelle spørsmålet, som var mer basert rundt: Hvordan måle RAM-bruk.

Jeg trodde jeg ville legge til, jeg har lagt til forskjellige nye seksjoner med kode de siste ukene, så optomised det til det fungerer, men nå har jeg bare lagt til en halv doz byte vars og jeg er ferdig ... :(
Bruker du typen 'String' i programmene dine? Dette er kjent for å utføre hyppige dynamiske minnetildelinger og utgivelser, som kan fragmentere haugen til det punktet hvor du ikke kan huske noe igjen.
@jfpoilpret Jeg holder meg borte fra `String`s på grunn av overhead. Jeg er glad for å jobbe med røyeoppsett, når det er sagt, jeg definerer nesten alltid alle røyerettene mine med en fast størrelse (for øyeblikket har jeg ETT byte-utvalg som ikke bare er fordi jeg endrer innholdslengden for forskjellige rekompiler.
Hvis du legger ut koden din her (eller på pastebin hvis den er for stor), kan du hekp finne ut hvilke problemer du har med minnet.
@jfpoilpret Jeg kan egentlig ikke legge inn koden, den er enorm og dessverre veldig oppblåst, spredt over 16 filer. Det var et prosjekt som jeg lot vokse godt utover det som var nødvendig (det er flere prosjekter slått sammen). Jeg begynner nå å bryte den fra hverandre, noe jeg sikkert er med på å løse problemet. Selv om det er noen deler av det, trenger jeg folk å se på (eller veilede meg videre), jeg legger dem ut senere.
kanskje du bare kan legge ut delen du har fjernet med `# ifndef`, som kan gi oss tips; et annet poeng: du har ikke nevnt hvilken Arduino du bruker. En liste over bibliotekene du bruker kan også være nyttig. Til slutt inkluderer produksjonen gitt av avude generelt (fungerer på Windows) størrelsen på statiske data, som kan hjelpe mye.
Selv om spørsmålet ditt virker relatert til minneforbruk for kjøretid, vil du vurdere å bruke 1.5.x-serien av Arduino IDE: den rapporterer mengden "statisk" RAM som brukes av skissen (variable erklæringer), rett etter kompilering. Det vil ikke være presist om koden din bruker malloc, men det er en start.
Ja, ok, jeg redigerer snart for å inkludere litt kode. Jeg har gjort så mange koteletter og endringer siden i går kveld, fjernet og justert ting og sett på `avr-size` og` avr-objdump` utgangene. Jeg legger opp koden som brøt kamelen tilbake
Jeg trodde bare jeg skulle legge til, jeg tror ikke det er noe iboende galt med koden ovenfor, faktisk, hvis jeg fjerner andre kodesegmenter, fungerer ovennevnte som forventet. Faktisk fungerer selve koden ALLTID som forventet. Den bryter andre steder i koden (i hovedsak bryter den seriell kommunikasjon som mottas).
Når det gjelder poenget ditt om `bss` og` data`: `data` initialiseres globale data som opprinnelig ligger i Flash og blir kopiert til SRAM ved programstart; `bss` er uinitialiserte globale data som bare finnes i SRAM. Derfor bruker begge SRAM helt. Det som er igjen i SRAM er for stabelen og dyngen.
Så betyr det at brukt SRAM en gang i gang, vil tilsvare minst .bss PLUS .data? eller er det noe overlapp?
Det er et PLUS, det er ingen overlapping (heldigvis vil jeg legge til!)
Fem svar:
alexan_e
2014-03-17 04:29:40 UTC
view on stackexchange narkive permalink

Du kan bruke funksjonene som følger med AVRGCC: Overvåking av stabelbruk

Funksjonen var ment å kontrollere stakkbruken, men det den rapporterer er faktisk RAM som aldri har blitt brukt (under henrettelse). Det gjøres ved å "male" (fylle) RAM-en med en kjent verdi (0xC5), og deretter sjekke RAM-området og telle hvor mange byte som fremdeles har samme opprinnelige verdi.
Rapporten viser RAM som ikke har vært brukt (minimum ledig RAM) og derfor kan du beregne maks RAM som er brukt (Total RAM - rapportert RAM).

Det er to funksjoner:

  • StackPaint utføres automatisk under initialisering og "maler" RAM-en med verdien 0xC5 (kan endres om nødvendig).

  • StackCount kan ringes når som helst for å telle RAM som ikke har blitt brukt.

Her er et eksempel på bruk. Gjør ikke mye, men er ment å vise hvordan du bruker funksjonene.

  // ------------ -------------------------------------------------- --------------- ekstern uint8_t _end; ekstern uint8_t __stack; ugyldig StackPaint (ugyldig) __attribute__ ((naken)) __attribute__ ((seksjon (".init1"))); ugyldig StackPaint ( ugyldig) {# if 0 uint8_t * p = &_end; mens (p < = &__stack) {* p = 0xc5; p ++; } #else __asm ​​flyktig ("ldi r30, lo8 (_end) \ n" "ldi r31, hi8 (_end) \ n" "ldi r24, lo8 (0xc5) \ n" / * STACK_CANARY = 0xc5 * / "ldi r25, hi8 (__ stack) \ n "" rjmp .cmp \ n "". loop: \ n "" st Z +, r24 \ n "" .cmp: \ n "" cpi r30, lo8 (__ stack) \ n "" cpc r31 , r25 \ n "" brlo .loop \ n "" breq .loop "::); # endif} uint16_t StackCount (void) {const uint8_t * p = &_end; uint16_t c = 0;
mens (* p == 0xc5 && p < = &__stack) {p ++; c ++; } returner c;} // ------------------------------------------- ---------------------------------- ugyldig oppsett () {Serial.begin (9600);} ugyldig sløyfe ( ) {// legg hovedkoden din her for å kjøre gjentatte ganger: Serial.println (StackCount (), DEC); // kaller StackCount () for å rapportere ubenyttet RAMdelay (1000);}  
interessant stykke kode, takk. Jeg brukte den, og det antyder at det er 600+ byte tilgjengelig, men når jeg begraver det i de dypere delene, reduseres det, men tørker ikke ut. Så Kanskje er problemet mitt andre steder.
@Madivad Merk at disse 600+ byte representerer den minste tilgjengelige mengden RAM opp til det punktet da du ringte StackCount. Det gjør egentlig ikke en forskjell hvor dypt du ringer, hvis flertallet av koden og nestede samtaler er utført før du ringer til StackCount, vil resultatet være riktig. Så for eksempel kan du la brettet fungere en stund (så lenge det tar å få nok kodedekning eller ideelt til du får den dårlige oppførselen du beskriver), og trykk deretter på en knapp for å få rapportert RAM. Hvis det er nok, er det ikke årsaken til problemet.
Takk @alexan_e, Jeg har opprettet et område på skjermen som rapporterer om dette nå, så når jeg går de neste dagene, vil jeg se dette nummeret med interesse, spesielt når det mislykkes! Takk igjen
@Madivad Vær oppmerksom på at den gitte funksjonen ikke vil rapportere riktige resultater hvis [malloc () brukes i koden] (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=365568&sid=e5ecab822bd4a3fd231659420b40330)
takk for det, det er jeg klar over, det har blitt nevnt. Så vidt jeg er klar over, bruker jeg den ikke (jeg vet at det kan være et bibliotek som bruker den, jeg har ikke sjekket helt ennå).
jfpoilpret
2014-03-18 01:38:39 UTC
view on stackexchange narkive permalink

Hovedproblemene du kan ha med minnebruk ved kjøretid er:

  • intet tilgjengelig minne i haugen for dynamiske tildelinger ( malloc eller ny)
  • ingen plass igjen på stacken når du ringer til en funksjon

Begge er faktisk samme som AVR SRAM (2K på Arduino) brukes til begge deler (i tillegg til statiske data som størrelsen aldri endres under gjennomføring av programmet).

Generelt brukes dynamisk minnetildeling sjelden på MCU-er, bare noen få biblioteker bruker den vanligvis (en av dem er String -klassen, som du nevnte at du ikke bruker, og det er et godt poeng).

Stakken og dyngen kan sees på bildet nedenfor (med tillatelse fra Adafruit): enter image description here

Derfor kommer det mest forventede problemet fra stack overløp (dvs. når bunken vokser mot dyngen og renner over den, og deretter - hvis bunken ikke ble brukt i det hele tatt - overflyter på den statiske datasonen til SRAM. tiden har du høy risiko for enten:

  • datakorrupsjon (dvs. stack ovewrites bunken eller statiske data), noe som gir deg uforståelig oppførsel For å vite hvor mye minne som er igjen mellom toppen av bunken og toppen av bunken (faktisk kan vi kalle det bunnen hvis vi representerer både bunken og bunken på det samme bildet som vist nedenfor), kan bruke følgende funksjon:
      int freeRam () {extern int __heap_start, * __ brkval; int v; returnere (int) &v - (__brkval == 0? (int) &__heap_start: (int) __brkval); }  

    I koden ovenfor peker __brkval til toppen av bunken, men er 0 når bunken ikke har blitt brukt, i så fall bruker vi &__heap_start som peker til __heap_start , den første variabelen som markerer bunnen av bunken; &v peker selvfølgelig til toppen av bunken (dette er den siste variabelen som ble presset på bunken), og derfor returnerer formelen ovenfor mengden minne som er tilgjengelig for stakken (eller bunken hvis du bruker den ) for å vokse.

    Du kan bruke denne funksjonen på forskjellige steder i koden din for å prøve å finne ut hvor denne størrelsen blir dramatisk redusert.

    Selvfølgelig, hvis du noen gang ser dette funksjon returnerer et negativt tall så er det for sent: du har allerede overfylt bunken!

Til moderatorer: beklager at jeg la dette innlegget til community-wiki, jeg må ha gjort noe galt mens jeg skrev, midt i innlegget. Vennligst legg den tilbake hit da denne handlingen var utilsiktet. Takk.
takk for dette svaret, jeg fant bokstavelig talt bare KODE for bare en time siden (nederst på http://playground.arduino.cc/Code/AvailableMemory#.UycOrueSxfg). Jeg har ikke tatt med det ennå (men det vil jeg) siden jeg har ganske stort område for feilsøking på skjermen. Jeg tror jeg har vært forvirret om dynamisk tildeling av ting. Er `malloc` og` new` den eneste måten jeg kan gjøre det på? I så fall har jeg ikke noe dynamisk. Jeg har nettopp lært at UNO har 2K SRAM. Jeg trodde det var 1K. Når jeg tar disse i betraktning, går jeg ikke tom for RAM! Jeg må lete andre steder.
I tillegg er det også `calloc`. Men du bruker kanskje tredjepartsbiblioteker som bruker dynamisk tildeling uten at du vet (du må sjekke kildekoden for alle avhengighetene dine for å være sikker på det)
Interessant. Det eneste "problemet" er at den rapporterer om ledig RAM på det punktet der den heter, så med mindre den er plassert i høyre del, vil du kanskje ikke merke en overkjøring av stakken. Funksjonen jeg har levert ser ut til å ha en fordel i det området siden den rapporterer min ledig RAM frem til det tidspunktet, når en RAM-adresse har blitt brukt, rapporteres den ikke lenger lenger (på undersiden kan det være noe okkupert RAM byte som samsvarer med "malings" -verdien og rapporteres som gratis). Bortsett fra det, passer kanskje den ene måten bedre enn den andre, avhengig av hva en bruker ønsker.
Godt poeng! Jeg hadde ikke lagt merke til dette spesifikke punktet i svaret ditt (og for meg som faktisk så ut som en feil), nå ser jeg poenget med å "male" frisonen på forhånd. Kanskje du kan gjøre dette poenget mer eksplisitt i svaret ditt?
Jeg lurer på om Serial.print () -funksjonene fremdeles vil fungere etter 'freeRam ()' - funksjonen fordi det * kanskje * ikke er for sent. Kanskje du kan ha en ISR-samtale freeRam (), og hvis den er negativ, skriv en melding til seriell skjerm. Det jeg ikke vet er om du også kunne rapportere om størrelsen på dyngen eller stakken.
Det anbefales ikke å bruke 'Serial' fra en ISR. Problemet når `freeRam ()` returnerer en negativ verdi, er at stabelen allerede har overflyttet over bunken (eller det motsatte), noe som betyr at noen data har blitt modifisert uventet. hvis dette er dyngen som fyller bunken, vil det sannsynligvis bli en overhengende krasj. Tvert imot har du kanskje ikke et krasj, men noen potensielt viktige data ville blitt ødelagt.
jippie
2014-03-17 01:31:21 UTC
view on stackexchange narkive permalink

Når du finner ut hvordan du finner den genererte .elf-filen i den midlertidige katalogen din, kan du utføre kommandoen nedenfor for å dumpe en SRAM-bruk, der project.elf skal erstattes med den genererte . selv fil. Fordelen med denne utgangen er muligheten til å inspisere hvordan SRAM-en din blir brukt. Må alle variablene være globale, er de egentlig alle nødvendige?

  avr-objdump -S -j .bss project.elfproject.elf: filformat elf32-avrDemontering av seksjon .bss: 00800060 <__bss_start>: ... 00800070 <measurementReady>: ... 00800071 <cycles>: ... 00800073 <measurement>: 800 073: 00 00 00 00 .... 00800077 <measurementStart>: 800 077: 00 00 00 00 .... 0080007b <timerOverflows>: 80007b: 00 00 00 00  

Legg merke til at dette ikke viser bruk av stakk eller dynamisk minne, slik Ignacio Vazquez-Abrams bemerket i kommentarene nedenfor.

I tillegg en avr -objdump -S -j .data project.elf kan sjekkes, men ingen av programmene mine sender ut noe med det, så jeg kan ikke vite helt sikkert om det er nyttig. Den skal liste '' initialiserte (ikke-null) data ''.

Eller du kan bare bruke `avr-size`. Men det vil ikke vise deg dynamiske tildelinger eller stakkbruk.
@IgnacioVazquez-Abrams om dynamikken, den samme for løsningen min. Redigerte svaret mitt.
Ok, dette er det mest interessante svaret så langt. Jeg har eksperimentert med `avr-objdump` og` avr-size`, og jeg vil redigere innlegget mitt snart. Takk for dette.
asheeshr
2014-03-16 20:15:03 UTC
view on stackexchange narkive permalink

Jeg mistenkte en stund at jeg kom til slutten av tilgjengelig RAM. Jeg tror ikke jeg bruker for mye stack (selv om det er mulig). Hva er den beste måten å bestemme hvor mye RAM jeg faktisk bruker?

Det er best å bruke en kombinasjon av manuell estimering og ved å bruke operatøren sizeof . Hvis alle erklæringene dine er statiske, bør dette gi deg et nøyaktig bilde.

Hvis du bruker dynamiske tildelinger, kan det hende du får et problem når du begynner å distribuere minnet. Dette skyldes minnefragmentering på dyngen.

Når jeg går gjennom og prøver å finne ut av det, har jeg problemer når jeg kommer til enums og strukturer; hvor mye minne koster de?

En enum tar like mye plass som en int . Så hvis du har et sett med 10 elementer i en enum -erklæring, vil det være 10 * sizeof (int) . Dessuten er hver variabel som bruker en oppregning ganske enkelt en int.

For strukturer ville det være enklest å bruke sizeof for å finne ut av det. Strukturer opptar et (minimum) rom som tilsvarer summen av medlemmene. Hvis kompilatoren strukturerer justering, kan det være mer, men dette er lite sannsynlig i tilfelle avr-gcc .

Jeg tildeler statisk alt så langt jeg kan. Jeg tenkte aldri på å bruke `sizeof` til dette formålet. For øyeblikket har jeg nesten 400 byte allerede gjort rede for (globalt). Nå skal jeg gå gjennom og beregne enumene (manuelt) og strengene (som jeg har noen av - og jeg vil bruke `sizeof '), og rapportere tilbake.
Ikke sikker på at du virkelig trenger `sizeof` for å vite størrelsen på de statiske dataene dine, ettersom dette blir skrevet ut av avrdude IIRC.
@jfpoilpret Det er versjonsavhengig, tror jeg. Ikke alle versjoner og plattformer gir det. Mine (Linux, flere versjoner) viser ikke minnebruk for en, mens Mac-versjoner gjør det.
Jeg har søkt på det utførlige resultatet, jeg trodde det skulle være der, det er det ikke
@AsheeshR Jeg var ikke klar over det, mitt fungerer bra på Windows.
sa_leinad
2018-06-14 18:40:13 UTC
view on stackexchange narkive permalink

Det er et program som heter Arduino Builder som gir en fin visualisering av mengden flash, SRAM og EEPROM som programmet ditt bruker.

Arduino Builder

Arduino-byggherren utgjør en del av CodeBlocks Arduino IDE -løsningen. Den kan brukes som enten et frittstående program eller gjennom CodeBlocks Arduino IDE.

Dessverre er Arduino Builder litt gammel, men den skal fungere for de fleste programmer og de fleste Arduinos, som f.eks. Uno.



Denne spørsmålet ble automatisk oversatt fra engelsk.Det opprinnelige innholdet er tilgjengelig på stackexchange, som vi takker for cc by-sa 3.0-lisensen den distribueres under.
Loading...