Küsimus:
Ma kasutan liiga palju RAM-i. Kuidas seda saab mõõta?
Madivad
2014-03-16 20:00:54 UTC
view on stackexchange narkive permalink

Tahaksin teada, kui palju RAM-i oma projektis kasutan, niipalju kui oskan öelda, pole seda kuidagi võimalik tegelikult välja töötada (peale selle, et ma ise selle läbi vaatan ja arvutan). Olen jõudnud üsna suure projekti etapini, kus olen kindlaks teinud, et mul on RAM-i otsas.

Olen selle kindlaks määranud, kuna saan lisada jaotise ja siis vabaneb kõik põrgu mujal minu koodis ilma nähtava põhjuseta. Kui ma #ifndef midagi muud välja panen, töötab see uuesti. Uuel koodil pole programmeeritavalt viga.

Kahtlesin mõnda aega, et jõudsin saadaoleva RAM-i lõpuni. Ma ei usu, et kasutan liiga palju virna (ehkki see on võimalik), mis on parim viis kindlaks teha, kui palju RAM-i tegelikult kasutan?

Läbi vaadates proovin selle välja töötada mul on probleeme, kui jõuan loenditesse ja juhatusteni; kui palju mälu need maksavad?

esimene redigeerimine: KA, olen algusest peale oma eskiisi nii palju redigeerinud, need pole tegelikud tulemused, mille ma algselt sain, kuid need on need, mida ma nüüd saan.

  tekstiandmed bss dec hex failinimi 17554 844 449 18847 499f HA15_20140317w.cpp.elf 16316 694 409 17419 440b HA15_20140317w.cpp.elf 17346 790 426 18562 4882 HA15_20140317w.cpp.elf 

Esimene rida (tekstiga 17554) ei töötanud, pärast palju redigeerimist töötab teine ​​rida (tekstiga 16316) nii, nagu peaks.

edit: kolmandal real on kõik töötavad, jadalugemine, minu uued funktsioonid jne. Põhimõtteliselt eemaldasin mõned globaalsed muutujad ja duplikaadikoodi. Mainin seda sellepärast, et (nagu kahtlustatakse), see pole seotud selle koodiga sae kohta, vaid RAM-i kasutamisega. Mis toob mind tagasi algse küsimuse juurde: "kuidas seda kõige paremini mõõta", uurin siiski mõnda vastust, aitäh.

Kuidas ma ülaltoodud teavet tegelikult tõlgendan?

Siiani olen aru saanud:

  `TEXT` on programmi käsumälu
"DATA" on muutujad (ühtsustatud?) Programmimälus. "BSS" on muutujad, mis hõivavad RAM-i  

kuna BSS on tunduvalt väiksem kui 1024 baiti, miks teine ​​töötab, kuid esimene ei tööta " t? Kui see on DATA + BSS , siis mõlemad hõivavad rohkem kui 1024.

re-edit: redigeerisin küsimust koodi lisamiseks, kuid nüüd olen selle eemaldanud, kuna sellel polnud tegelikult probleemiga mingit pistmist (välja arvatud võib-olla kehvad kodeerimispraktikad, muutujadeklaratsioonid jms). Koodi saate muudatustest tagasi vaadates üle vaadata, kui soovite seda tõesti näha. Tahtsin naasta käsitletud küsimuse juurde, mis põhines pigem sellel: Kuidas mõõta RAM-i kasutamist.

Mõtlesin, et lisan, olen viimaste nädalate jooksul lisanud mitmeid uusi koodijagu, seejärel optimeerinud, kuni see töötab, kuid nüüd olen lisanud vaid pool tosinat baidivarsi ja olen valmis ... :(
Kas kasutate oma programmides tüüpi "String"? See teeb teadaolevalt sagedasi dünaamilisi mälumahutusi ja vabastusi, mis võivad killustiku killustada nii kaugele, et teil pole enam ühtegi mälu.
@jfpoilpret Hoian `Stringi`st eemal üldkulude tõttu. Olen õnnelik, kui töötan söemassiividega, see tähendab, et määratlen peaaegu alati kõik oma söemassiivid kindla suurusega (hetkel on mul ÜHE baidine massiiv, mis pole puhtalt sellepärast, et muudan erinevate ümberkompileerimiste sisu pikkust.
Koodi siia postitamine (või kui see on liiga suur aadressil pastebin) võib hekp teada saada, milliseid probleeme mäluga kokku puutute.
@jfpoilpret Ma ei saa seda koodi tegelikult postitada, see on tohutu ja kahjuks väga punnitatud, jaotatud 16 faili peale. See oli projekt, mille lubasin kasvada kaugemale sellest, mida nõuti (see on mitu ühte liidetud projekti). Hakkan seda nüüd lahku ajama, mis aitab kindlasti probleemi lahendada. Kuigi mul on mõningaid osi, mida ma vajan, et inimesed neid vaataksid (või juhendaksid), postitan need hiljem.
võib-olla võiksite lihtsalt postitada jaotise, mille olete eemaldanud koodiga "# ifndef", mis annab meile vihjeid; teine ​​punkt: te pole maininud, mida Arduino kasutate. Samuti võib olla kasulik teie kasutatavate raamatukogude loend. Lõpuks sisaldab avrdude antud väljund (töötab Windowsis) staatiliste andmete suurust, mis võib palju aidata.
Kuigi teie küsimus näib olevat seotud käitamismälu tarbimisega, peaksite kaaluma Arduino IDE 1.5.x-seeria kasutamist: see teatab eskiis ("muutujadeklaratsioonid") "staatilise" RAM-i kogusest kohe pärast kompileerimist. See pole täpne, kui teie kood kasutab malloci, kuid see on algus.
Jah, ok, ma muudan varsti koodi lisamiseks. Olen eelmisest õhtust alates teinud nii palju karbonaate ja muudatusi, eemaldanud ja näpistanud asju ning vaadanud `avr-size` ja` avr-objdump` väljundeid. Panen koodi üles, mis kaamelid tagasi murdis
Mõtlesin lihtsalt, et lisan, ma arvan, et ülaltoodud koodil pole midagi sisuliselt valesti. Tegelikult, kui eemaldan muud koodisegmendid, töötab ülaltoodu ootuspäraselt. Tegelikult töötab see kood ise ALATI ootuspäraselt. See Murdub mujal koodis (sisuliselt katkestab vastuvõetud seeriaside).
Mis puutub teie mõttesse "bss" ja "andmed" kohta: "andmed" on initsialiseeritud globaalsed andmed, mis algselt asuvad Flashis ja kopeeritakse programmi käivitamisel SRAM-i; "bss" on initsialiseerimata globaalsed andmed, mis eksisteerivad ainult SRAM-is. Seetõttu kasutavad mõlemad SRAM-i üldse. SRAM-i jääb üle virna ja kuhja.
Kas see tähendab, et kasutatud SRAM on juba käimas, võrduks vähemalt .bss PLUS .data-ga? või on mingi kattuvus?
See on PLUSS, kattumist pole (õnneks lisan!)
Viis vastused:
#1
+15
alexan_e
2014-03-17 04:29:40 UTC
view on stackexchange narkive permalink

Võite kasutada pakutavaid funktsioone AVRGCC: Virnade kasutamise jälgimine

Funktsioon oli mõeldud virna kasutamise kontrollimiseks, kuid see annab teada tegelikust RAM-ist, mida pole kunagi kasutatud (hukkamise ajal). Seda tehakse nii, et "värvitakse" (täidetakse) RAM teadaoleva väärtusega (0xC5) ja kontrollitakse seejärel RAM-i pindala, loendades, kui paljudel baitidel on endiselt sama algväärtus.
Aruandes kuvatakse RAM, mida pole veel kasutatud (minimaalne vaba RAM) ja selle jaoks saate arvutada kasutatud maksimaalse RAM-i (kogu RAM - teatatud RAM).

On kaks funktsiooni:

  • StackPaint käivitatakse lähtestamise ajal automaatselt ja "värvib" RAM-i väärtusega 0xC5 (vajadusel saab muuta).

  • StackCount Kasutamata RAM-i lugemiseks saab helistada igal ajal .

Siin on näide kasutamisest. Ei tee palju, kuid on mõeldud funktsioonide kasutamiseks.

  // ------------ -------------------------------------------------- --------------- extern uint8_t _end; extern uint8_t __stack; void StackPaint (void) __attribute__ ((alasti)) __attribute__ ((section (".init1"))); void StackPaint ( tühine) {# if 0 uint8_t * p = &_end; samas (p < = &__stack) {* p = 0xc5; p ++; } #else __asm ​​volatile ("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;
samas (* p == 0xc5 && p < = &__stack) {p ++; c ++; } return c;} // ------------------------------------------- ---------------------------------- void setup () {Serial.begin (9600);} void loop ( ) {// sisestage oma põhikood siia, et seda korduvalt käivitada: Serial.println (StackCount (), DEC); // kutsub StackCount () kasutamata RAM-i viivituse (1000) teatamiseks;}  
huvitav koodijupp, aitäh. Ma kasutasin seda ja see viitab sellele, et saadaval on üle 600 baiti, kuid kui ma matan, et sügavamates osades see küll väheneb, kuid ei kustu. Nii et VÕIB-olla on mu probleem mujal.
@Madivad Pange tähele, et see 600+ baiti tähistab minimaalset saadaolevat RAM-i kogust kuni hetkeni, mil helistasite StackCountile. Tegelikult pole vahet, kui sügavale kõne teete, kui enamus koodist ja pesastatud kõned on täidetud enne StackCountile helistamist, on tulemus õige. Nii võite näiteks jätta oma plaadi mõneks ajaks tööle (nii kaua, kui kulub piisava koodikatvuse saamiseks või ideaaljuhul seni, kuni saate kirjeldatud väärkäitumist) ja seejärel vajutada nuppu, et saada teatatud RAM-i. Kui neid on piisavalt, pole see probleemi põhjus.
Aitäh @alexan_e,. Olen loonud oma displeile ala, mis annab sellest praegu teada, nii et järgmise paari päeva jooksul edasi liikudes vaatan seda numbrit huviga, eriti kui see ebaõnnestub! Aitäh veel kord
@Madivad Pange tähele, et antud funktsioon ei teavita õigetest tulemustest, kui koodis kasutatakse [malloc ()] (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=365568&sid=e5ecab822bd4a3fd231659420b40
aitäh selle eest, olen teadlik, seda on mainitud. Minu teada ma seda ei kasuta (ma tean, et seda võib kasutada mõni teek, ma pole seda veel täielikult kontrollinud).
#2
+10
jfpoilpret
2014-03-18 01:38:39 UTC
view on stackexchange narkive permalink

Peamised probleemid, mis teil mälu kasutamisel käitamise ajal võib tekkida, on järgmised:

  • dünaamiliste eraldiste jaoks pole hunnikus vaba mälu ( malloc või new)
  • funktsiooni kutsumisel pole virnale jäänud ruumi

Mõlemad on tegelikult sama, mida AVR-i kasutatakse mõlema jaoks SRAM i (2K Arduinos) (lisaks staatilistele andmetele mille suurus ei muutu programmi käivitamisel).

Üldiselt kasutatakse dünaamilise mälu jaotust MCU-de puhul harva, tavaliselt kasutavad seda vaid üksikud teegid (üks neist on klass String , mida te mainisite, et te ei kasuta, ja see on hea punkt).

Virna ja kuhja on näha alloleval pildil ( Adafruit nõusolekul): enter image description here

Seega tuleb kõige oodatum probleem virnast ülevool (st kui virn kasvab kuhja poole ja voolab üle selle ning siis-kui hunnikut üldse ei kasutatud - ülevool SRAM-i staatilises andmevööndis. Ajal on teil suur oht:

  • andmete rikkumine (st. virn kirjutab üle kuhja või staatilisi andmeid), mis annab teile arusaamatu käitumise
  • korstna rikutud (st kuhja või staatilised andmed kirjutavad virna sisu üle), mis põhjustab üldiselt krahhi

Hunniku ülaosa ja virna ülaosa vahele jäänud mäluhulga teadmiseks (tegelikult võiksime seda nimetada alumiseks, kui kujutame nii kuhja kui ka virna samal pildil, nagu allpool kujutatud), peate saab kasutada järgmist funktsiooni:

  int freeRam () {extern int __heap_start, * __ brkval; int v; return (int) &v - (__brkval == 0? (int) &__heap_start: (int) __brkval); }  

Ülaltoodud koodis osutab __brkval kuhja ülaosale, kuid on 0 , kui kuhja pole kasutatud, sellisel juhul kasutame &__heap_start mis osutab esimesele muutujale, mis tähistab kuhja põhja; __heap_start ; &v osutab muidugi virna ülaosale (see on viimane virnale lükatud muutuja), seega tagastab ülaltoodud valem virnale (või hunnikule, kui te seda kasutate) saadaoleva mälumahu ) kasvamiseks.

Seda funktsiooni saate kasutada oma koodi erinevates kohtades, et proovida, kus see suurus dramaatiliselt väheneb.

Muidugi, kui te seda kunagi näete funktsioon tagastab negatiivse arvu, siis on juba liiga hilja: olete juba virna üle ajanud!

Moderaatoritele: vabandust, et panin selle postituse kogukonna vikisse, pidin kirjutamise ajal postituse keskel midagi valesti tegema. Pange see siia tagasi, kuna see tegevus oli tahtmatu. Aitäh.
aitäh selle vastuse eest, leidsin sõna otseses mõttes JUST lihtsalt selle kooditüki vaevalt tund tagasi (saidi http://playground.arduino.cc/Code/AvailableMemory#.UycOrueSxfg allservas). Ma pole seda veel lisanud (aga lisan), kuna mul on ekraanil üsna suur silumisala. Ma arvan, et olen dünaamiliselt määranud asju segaduses. Kas "malloc" ja "uus" on ainus viis, kuidas seda teha? Kui jah, siis pole mul midagi dünaamilist. Samuti sain just teada, et UNO-l on 2K SRAM-i. Ma arvasin, et see on 1K. Neid arvesse võttes ei ole mul RAM-i otsas! Ma pean mujalt otsima.
Lisaks on ka `calloc`. Kuid võite kasutada kolmanda osapoole lib-e, mis kasutavad dünaamilist jaotust ilma teie teadmata (selles veendumiseks peate kontrollima kõigi oma sõltuvuste lähtekoodi)
Huvitav. Ainus "probleem" on see, et see teatab vaba RAM-ist kohas, kus seda kutsutakse, nii et kui see pole paigutatud paremasse ossa, ei pruugi te pinu ületamist märgata. Tundub, et minu pakutud funktsioonil on selles piirkonnas eelis, kuna see teatab minimaalsest vaba RAM-ist kuni selle hetkeni, kui RAM-i aadressi on kasutatud, ei teatata sellest enam tasuta (allpool võib olla hõivatud RAM baidid, mis vastavad "värvi" väärtusele ja on kajastatud tasuta). Peale selle sobib võib-olla üks viis paremini kui teine, sõltuvalt kasutaja soovist.
Hea tähelepanek! Ma ei olnud teie vastuses seda konkreetset punkti märganud (ja minu jaoks tundus see tegelikult veana), nüüd näen mõtet vabatsooni "värvida" ette. Võib-olla saaksite selle vastuse selgemaks muuta?
Huvitav, kas funktsioonid Serial.print () töötaksid ka pärast funktsiooni 'freeRam ()', sest see ei pruugi olla * liiga hilja. Võib-olla võiksite saada ISR-i kõne freeRam () ja kui see on negatiivne, kirjutage seeriamonitorile teade. Mida ma ei tea, on see, kas võiksite aru anda ka kuhja või virna suuruste kohta.
ISR-ist ei soovitata kasutada "seeriat". Kui "freeRam ()" tagastab negatiivse väärtuse, on see, et virn on juba üle kuhja (või vastupidi) üle lennanud, mis tähendab, et mõnda teavet on ootamatult muudetud. kui see on hunnik, mis virna üle ajab, saab sellest tõenäoliselt peatselt kukkumine. Vastupidi, teil ei pruugi krahhi olla, kuid mõned potentsiaalselt olulised andmed oleks hävitatud.
#3
+7
jippie
2014-03-17 01:31:21 UTC
view on stackexchange narkive permalink

Kui saate aru, kuidas ajutises kataloogis genereeritud .elf-fail leida, võite SRAM-i kasutamise tühjendamiseks täita alloleva käsu, kus project.elf tuleb asendada loodud fail .elf . Selle väljundi eeliseks on võime kontrollida, kuidas teie SRAM-i kasutatakse. Kas kõik muutujad peavad olema globaalsed, kas need on kõik vajalikud?

  avr-objdump -S -j .bss project.elfproject.elf: failivorming elf32-avr Jao .bss demonteerimine: 00800060 <__bss_start>: ... 00800070 <measurementReady>: ... 00800071 <cycles>: ... 00800073 <measurement>: 800073: 00 00 00 00 .... 00800077 <measurementStart>: 800077: 00 00 00 00 .... 0080007b <timerOverflows>: 80007b: 00 00 00 00  

Pange tähele, et see ei näita virna ega dünaamilise mälu kasutamist, nagu märkis Ignacio Vazquez-Abrams allpool toodud kommentaarides.

Lisaks avr -objdump -S -j .data project.elf saab kontrollida, kuid ükski minu programmidest ei väljastata sellega midagi, nii et ma ei saa kindlalt öelda, kas see on kasulik. See peaks loetlema 'initsialiseeritud (nullist erinevad) andmed.

Või võite lihtsalt kasutada `avr-size`. Kuid see ei näita teile dünaamilisi jaotusi ega virna kasutamist.
@IgnacioVazquez-Abrams dünaamika kohta, minu lahenduse puhul sama. Redigeeris mu vastust.
Ok, see on seni kõige huvitavam vastus. Olen katsetanud funktsioone "avr-objdump" ja "avr-size" ning redigeerin oma ülaltoodud postitust varsti. Tänan selle eest.
#4
+3
asheeshr
2014-03-16 20:15:03 UTC
view on stackexchange narkive permalink

Kahtlesin mõnda aega, et jõudsin saadaoleva RAM-i lõpuni. Ma arvan, et ma ei kasuta liiga palju virna (kuigi see on võimalik), mis on parim viis määrata, kui palju RAM-i tegelikult kasutan?

Parim oleks kasutada kombinatsioon manuaalsest hinnangust ja operaatori sizeof abil. Kui kõik teie deklaratsioonid on staatilised, peaks see andma teile täpse pildi.

Kui kasutate dünaamilisi jaotusi, võib teil tekkida probleem, kui alustate mälu jaotamist. Selle põhjuseks on hunniku mälu killustatus.

Läbides ja üritades seda lahendada, on mul probleeme, kui jõuan loenditesse ja ülesehitustesse; kui palju mälu need maksavad?

Enum võtab sama palju ruumi kui int . Niisiis, kui teil on enum -deklaratsioonis 10 elementi, oleks see 10 * sizeof (int) . Samuti on iga loendit kasutav muutuja lihtsalt int.

Struktuuride jaoks oleks kõige lihtsam teada saada sizeof . Konstruktsioonid hõivavad (minimaalse) ruumi, mis võrdub selle liikmete summaga. Kui kompilaator teeb struktuuri joondamise, siis võib see olla rohkem, kuid see on avr-gcc puhul vähetõenäoline.

Ma määran kõik staatiliselt nii palju kui võimalik. Ma ei mõelnud kunagi selleks, et `sizeof`i kasutada. Praegu on mul (globaalselt) juba arvestatud peaaegu 400 baiti. Nüüd vaatan läbi ja loen arvud (käsitsi) ja struktuurid (millest mul on vähe - ja kasutan `sizeof`) ning annan aru.
Pole kindel, kas teil on staatiliste andmete suuruse teadmiseks tõesti vaja "sizeof", kuna need avrdude IIRC välja printib.
@jfpoilpret Ma arvan, et see sõltub versioonist. Kõik versioonid ja platvormid seda ei paku. Minu oma (Linux, mitu versiooni) ei näita ühe jaoks mälukasutust, Maci versioonid aga küll.
Olen otsinud verbose väljundit, arvasin, et see peaks seal olema, seda pole
@AsheeshR Ma polnud sellest teadlik, minu Windowsis töötab hästi.
#5
+1
sa_leinad
2018-06-14 18:40:13 UTC
view on stackexchange narkive permalink

On olemas programm nimega Arduino Builder, mis kuvab kenasti teie programmi kasutatava välgu, SRAM-i ja EEPROM-i hulga.

Arduino Builder

Arduino ehitaja moodustab osa CodeBlocks Arduino IDE lahendusest. Seda saab kasutada kas eraldiseisva programmina või CodeBlocks Arduino IDE kaudu.

Kahjuks on Arduino Builder veidi vana, kuid see peaks töötama enamiku programmide ja enamiku Arduinode puhul, näiteks Uno.



See küsimus ja vastus tõlgiti automaatselt inglise keelest.Algne sisu on saadaval stackexchange-is, mida täname cc by-sa 3.0-litsentsi eest, mille all seda levitatakse.
Loading...