Chciałbym wiedzieć, ile pamięci RAM używam w swoim projekcie, o ile mogę stwierdzić, że nie ma sposobu, aby to naprawdę rozwiązać (oprócz samodzielnego przejrzenia i obliczenia). Doszedłem do etapu w dość dużym projekcie, w którym ustaliłem, że brakuje mi pamięci RAM.
Ustaliłem to, ponieważ mogę dodać sekcję, a potem piekło rozpada się gdzie indziej w moim kodzie bez wyraźnego powodu. Jeśli mam #ifndef
coś innego, to znowu działa. Z nowym kodem nie ma nic programowo niepoprawnego.
Przez chwilę podejrzewałem, że zbliżam się do końca dostępnej pamięci RAM. Nie sądzę, że używam zbyt dużo stosów (chociaż jest to możliwe), jaki jest najlepszy sposób na określenie, ile pamięci RAM faktycznie używam?
Przechodząc i próbując to wypracować, mam problemy, gdy dochodzę do wyliczeń i struktur; ile kosztują pamięci?
pierwsza edycja: RÓWNIEŻ edytowałem szkic od samego początku, to nie są rzeczywiste wyniki, które początkowo otrzymałem, ale to, co teraz otrzymuję.
text data bss dec hex filename
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
Pierwszy wiersz (z tekstem 17554) nie działał, po wielu edycjach drugi wiersz (z tekstem 16316) działa tak, jak powinien.
edycja: trzeci wiersz ma wszystko, co działa, odczyt szeregowy, moje nowe funkcje itp. Zasadniczo usunąłem niektóre zmienne globalne i zduplikowałem kod. Wspominam o tym, ponieważ (jak podejrzewam) nie chodzi o ten kod per sae, musi dotyczyć użycia pamięci RAM. To prowadzi mnie z powrotem do pierwotnego pytania: „jak najlepiej to zmierzyć”. Wciąż sprawdzam kilka odpowiedzi, dzięki.
Jak właściwie interpretować powyższe informacje?
Jak dotąd rozumiem:
`TEXT` is program instruction memory
`DATA` is variables (unitialised?) in program memory
`BSS` is variables occupying RAM
skoro BSS ma znacznie mniej niż 1024 bajty, dlaczego drugi działa, a pierwszy nie? Jeśli tak, DATA+BSS
oba zajmują więcej niż 1024.
reedycja: Zredagowałem pytanie, aby dołączyć kod, ale teraz go usunąłem, ponieważ tak naprawdę nie miało to nic wspólnego z problemem (poza może złymi praktykami kodowania, deklaracjami zmiennych i tym podobnymi). Możesz przejrzeć kod, przeglądając wprowadzone zmiany, jeśli naprawdę chcesz go zobaczyć. Chciałem wrócić do pytania, które było bardziej oparte na: Jak zmierzyć zużycie pamięci RAM.
String
pisania w swoich programach? Jest to znane z częstego przydzielania i zwalniania pamięci dynamicznej, co może rozdrobnić stertę do punktu, w którym może nie pozostać żadna pamięć.String
s z powodu narzutu. Z przyjemnością pracuję z tablicami znaków, co powiedziawszy, prawie zawsze definiuję wszystkie moje tablice znaków z ustalonym rozmiarem (w tej chwili mam JEDNĄ tablicę bajtów, która nie jest czysta, ponieważ zmieniam długość zawartości dla różnych rekompilacji.Odpowiedzi:
Możesz użyć dostarczonych funkcji AVRGCC: Monitorowanie użycia stosu
Ta funkcja miała na celu sprawdzenie użycia stosu, ale zgłasza rzeczywistą pamięć RAM, która nigdy nie była używana (podczas wykonywania). Robi to poprzez „malowanie” (wypełnianie) pamięci RAM znaną wartością (0xC5), a następnie sprawdzanie obszaru pamięci RAM, licząc, ile bajtów ma wciąż tę samą wartość początkową.
Raport pokaże pamięć RAM, która nie została wykorzystana (minimalna ilość wolnej pamięci RAM) i dlatego możesz obliczyć maksymalną pamięć RAM, która została wykorzystana (Całkowita pamięć RAM - zgłoszona pamięć RAM).
Istnieją dwie funkcje:
StackPaint jest wykonywany automatycznie podczas inicjalizacji i „maluje” pamięć RAM wartością 0xC5 (w razie potrzeby można ją zmienić).
StackCount można wywołać w dowolnym momencie, aby policzyć pamięć RAM, która nie była używana.
Oto przykład użycia. Nie robi wiele, ale ma na celu pokazać, jak korzystać z funkcji.
źródło
Główne problemy związane z użyciem pamięci w środowisku wykonawczym to:
malloc
lubnew
)Oba są w rzeczywistości takie same, jak AVR SRAM (2K na Arduino) jest używany dla obu (oprócz danych statycznych, których rozmiar nigdy się nie zmienia podczas wykonywania programu).
Zasadniczo dynamiczna alokacja pamięci jest rzadko używana na MCU, zazwyczaj korzysta z niej tylko kilka bibliotek (jedna z nich to
String
klasa, o której wspomniałeś, że nie używasz, i to jest dobry punkt).Stos i stos można zobaczyć na poniższym obrazku (dzięki uprzejmości Adafruit ):
Dlatego najbardziej oczekiwanym problemem jest przepełnienie stosu (tj. Gdy stos rośnie w kierunku stosu i przepełnia się nim, a następnie - jeśli stos nie był w ogóle używany - przepełnienia w strefie danych statycznych SRAM. W tym czasie masz wysokie ryzyko:
Aby poznać ilość pamięci pozostałej między górą stosu a górą stosu (w rzeczywistości możemy nazwać to dnem, jeśli reprezentujemy zarówno stos, jak i stos na tym samym obrazie, jak pokazano poniżej), należy może korzystać z następującej funkcji:
W powyższym kodzie
__brkval
wskazuje na górę stosu, ale0
wtedy, gdy stos nie został użyty, w którym to przypadku używamy,&__heap_start
które punkty wskazują__heap_start
pierwszą zmienną, która oznacza spód stosu;&v
wskazuje oczywiście na górę stosu (jest to ostatnia zmienna wypychana na stos), stąd powyższa formuła zwraca ilość pamięci dostępnej dla stosu (lub stosu, jeśli go używasz) do powiększenia.Możesz użyć tej funkcji w różnych lokalizacjach kodu, aby dowiedzieć się, gdzie ten rozmiar dramatycznie się zmniejsza.
Oczywiście, jeśli kiedykolwiek zobaczysz, że ta funkcja zwraca liczbę ujemną, jest już za późno: już przepełniłeś stos!
źródło
malloc
inew
jedyny sposób mogę to zrobić? Jeśli tak, to nie mam nic dynamicznego. Właśnie dowiedziałem się, że UNO ma 2K SRAM. Myślałem, że to 1K. Biorąc to pod uwagę, nie brakuje mi pamięci RAM! Muszę szukać gdzie indziej.calloc
. Ale możesz używać bibliotek innych firm, które korzystają z alokacji dynamicznej bez Twojej wiedzy (musisz sprawdzić kod źródłowy wszystkich swoich zależności, aby się tego upewnić)Kiedy zastanawiasz się, jak zlokalizować wygenerowany plik .elf w katalogu tymczasowym, możesz wykonać poniższe polecenie, aby zrzucić użycie pamięci SRAM i
project.elf
zastąpić je wygenerowanym.elf
plikiem. Zaletą tego wyjścia jest możliwość sprawdzenia, w jaki sposób używana jest pamięć SRAM. Czy wszystkie zmienne muszą być globalne, czy naprawdę wszystkie są wymagane?Zauważ, że nie pokazuje to wykorzystania pamięci dynamicznej i pamięci, jak zauważył Ignacio Vazquez-Abrams w komentarzach poniżej.
Dodatkowo
avr-objdump -S -j .data project.elf
można sprawdzić, ale żaden z moich programów nic z tym nie wypisuje, więc nie jestem pewien, czy jest to przydatne. To ma listy „zainicjowana (niezerowej) dane”.źródło
avr-size
. Ale to nie pokazuje dynamicznych alokacji ani użycia stosu.avr-objdump
iavr-size
wkrótce będę edytować swój post powyżej. Dzięki za to.Najlepiej byłoby zastosować kombinację ręcznego oszacowania i
sizeof
operatora. Jeśli wszystkie deklaracje są statyczne, powinno to dać dokładny obraz.Jeśli używasz alokacji dynamicznych, możesz napotkać problem po rozpoczęciu zwalniania pamięci. Wynika to z fragmentacji pamięci na stercie.
Wyliczenie zajmuje tyle samo miejsca co
int
. Tak więc, jeśli masz zestaw 10 elementów wenum
deklaracji, byłoby to10*sizeof(int)
. Ponadto każda zmienna korzystająca z wyliczenia jest po prostu anint
.W przypadku struktur najłatwiej byłoby
sizeof
to sprawdzić. Struktury zajmują (minimalną) przestrzeń równą sumie jej elementów. Jeśli kompilator wykonuje wyrównanie struktury, może być więcej, jednak jest to mało prawdopodobne w przypadkuavr-gcc
.źródło
sizeof
do tego celu. W tej chwili mam już prawie 400 bajtów (globalnie). Teraz przejdę i obliczyć wyliczenia (ręcznie) i struktury (których mam kilka - i użyjęsizeof
), i przekażę raport.sizeof
znać rozmiar swoich danych statycznych, ponieważ są one drukowane przez avrdude IIRC.Istnieje program o nazwie Arduino Builder, który zapewnia schludną wizualizację ilości pamięci flash, SRAM i EEPROM, z których korzysta Twój program.
Konstruktor Arduino stanowi część rozwiązania IDE CodeBlocks Arduino . Może być używany jako samodzielny program lub za pomocą CodeBlocks Arduino IDE.
Niestety Arduino Builder jest trochę stary, ale powinien działać dla większości programów i większości Arduinos, takich jak Uno.
źródło