Czy istnieje wada polegająca na przydzielaniu ogromnej ilości stosu dla pojedynczej tablicy w systemie osadzonym?


12

Zwykle nie mam problemu z podjęciem decyzji, czy niektóre dane muszą być globalne, statyczne czy na stosie (tutaj nie ma alokacji dynamicznej, więc nie ma zastosowania sterty). Przeczytałem również kilka pytań / odpowiedzi, takich jak to, ale moje pytanie jest bardziej szczegółowe, ponieważ wymaga ogromnej ilości danych, ogromnych w porównaniu do pamięci systemowej.

Pracuję nad istniejącym kodem, który próbuję ulepszyć (projekt, możliwe problemy, wydajność itp.). Ten kod działa na starym 8-bitowym MCU z tylko 4KB pamięci RAM . W tym kodzie mam do czynienia z tablicą o wielkości prawie 1 KB (tak, 1 KB w systemie RAM 4KB ). Używany jest każdy bajt tej tablicy, to nie jest pytanie. Problem polega na tym, że tablica ta jest statyczną tablicą w pliku, w którym została zadeklarowana, więc jej cykl życia jest taki sam jak w programie (tzn. Można ją uznać za nieskończoną).

Jednak po przeczytaniu kodu właśnie dowiedziałem się, że ta tablica nie potrzebuje nieskończonego cyklu życia, jest zbudowana i obsługiwana w sposób w pełni proceduralny, więc powinniśmy być w stanie zadeklarować ją tylko w funkcji, w której jest używana, w ten sposób byłby na stosie, a zatem zapisalibyśmy ten 1KB pamięci RAM.

Teraz pytanie: czy to byłby dobry pomysł? Z punktu widzenia projektu, jeśli nie potrzebuje nieskończonego / globalnego cyklu życia, należy do stosu. Ale hej, to 1KB na 4KB, czy nie ma żadnej wady przydzielania 25% pamięci RAM w ten sposób? (może to być 50% lub więcej stosu)

Czy ktoś może podzielić się doświadczeniem z tego rodzaju sytuacją, czy może ktoś pomyśli o jakimkolwiek ważnym celu, aby nie umieszczać tej tablicy na stosie? Szukam wad technicznych, a także komentarzy do projektu.

Jedyne, co mam świadomość, to to, że muszę upewnić się, że faktycznie mam 1 KB wolnego stosu, wchodząc w tę funkcję. Może to wszystko, co muszę zrobić, może nie.


4
Napisałeś: „i dlatego zachowaj 1 KB pamięci RAM”. Zachowaj to na co? Że 1KB musi być dostępny, gdy potrzebujesz go dla tablicy, więc dlaczego nie dokonać statycznego przydziału? Czy masz inne zastosowanie dla pamięci, gdy nie jest ona potrzebna dla tablicy?
kkrambo,

@kkrambo W pewnym momencie uważamy, że system jest pełny, gdy nie możemy dodać nic więcej do pamięci RAM, czy to coś statycznego, czy na stosie. Gdybyśmy umieścili tę tablicę na stosie tylko wtedy, gdy z niej korzystamy, pozwoliłaby ona na inną funkcjonalność, o ile nie byłyby używane jednocześnie. Ale pytanie jest całkowicie uzasadnione, w tej chwili, jeśli nic nie zmienimy w SW, nie potrzebujemy więcej pamięci RAM;)
Tim

1
Czy możesz wyjaśnić, czy ta tablica ma treść, która zawsze pozostaje taka sama, czy też zmienia się, gdy wywoływana jest funkcja, która z niej korzysta?
Blrfl,

@Blrfl Zmienia się przy każdym wywołaniu funkcji.
Tim

Odpowiedzi:


8

Jedyne, co mam świadomość, to to, że muszę upewnić się, że faktycznie mam 1 KB wolnego stosu, wchodząc w tę funkcję.

Tak, i to jest silne ograniczenie. Lepiej statystycznie upewnij się, że na stosie jest tak dużo miejsca. Jeśli kod jest mały, jeśli używasz najnowszego GCC do kompilacji kodu, zobacz to .

BTW, niektóre tanie mikroprocesory mogą wykorzystywać „dużą” ramkę wywoławczą bardziej kosztowną niż „normalną” (np. Ponieważ ich zestaw instrukcji wolałby przesunięcie o jeden bajt od wskaźnika stosu). YMMV.

Ponadto, jeśli kodujesz w C i uważasz, że twoja duża tablica może zostać ponownie wykorzystana do innych celów, możesz rozważyć utworzenie jej elementu unii (z globalną zmienną uniontypu). Tak, to jest dość brzydkie.

Alternatywnie, możesz rozważyć kodowanie jakiegoś prymitywnego alokatora sterty odpowiedniego dla twojej aplikacji (i może mieć interfejs API inny niż malloc& free...).


1
Dziękuję, tak naprawdę trochę oczekiwałem tego rodzaju odpowiedzi, tj. Zachowaj ją statycznie przydzieloną, aby mieć pewność, że nie skończę z przepełnieniem stosu. Niestety nie mam najnowszego kompilatora GCC, a kod nie jest mały.
Tim

Czy nie możesz uzyskać (być może kompilując GCC z jego kodu źródłowego) kompilatora GCC na swoją platformę?
Basile Starynkevitch

2
Mam już jeden, jest naprawdę stary. Praca nad nowym nie leży w moim zasięgu i nie pasuje do mojego harmonogramu. Ale jasne, niektóre rzeczy byłyby łatwiejsze dzięki nowoczesnym narzędziom.
Tim

3
Poproszenie szefa, by dał ci nowszą wersję GCC (albo poprzez dostarczenie ci aktualnych narzędzi binarnych, albo dając ci czas na rekompilację GCC) jest warte IMHO, ponieważ całkiem możliwe, że nowsza GCC zoptymalizowałaby się nieco lepiej (o czym wiesz gcc -flto -Os? ) i możesz zyskać trochę pamięci ...
Basile Starynkevitch

2
Jest na dobrej drodze, ale to nie nastąpi wcześniej. Już używam -O na innych systemach z nowszymi łańcuchami narzędzi, ale nie byłem świadomy tego parametru -flto, dziękuję za wskazanie go. (Zauważ, że kilka tygodni temu przeprowadziłem kilka testów z parametrami GCC -Os i -O1-3 na GCC 5.4.1, a pamięć RAM była taka sama przez cały czas. FLASH i MCU działały jednak inaczej. To nie było na tym samym MCU, o którym wspomniałem w tym pytaniu)
Tim

6

Ludzie często zachowują ostrożność przy dużym stosie, ponieważ rośnie on w pamięci RAM i zastępuje wartości zmiennych, co prowadzi do niewyjaśnionego zachowania. Jest jeszcze gorzej, ponieważ musisz znać najniższy możliwy adres wskaźnika stosu i odjąć rozmiar, który chcesz przydzielić, wchodząc w procedurę.

To wszystko jest zadaniem zarządzania pamięcią sprzętową (powinno generować pułapki lub błędy, gdy nastąpi przepełnienie stosu) lub kompilatora, biorąc pod uwagę, że ma on funkcje tego rodzaju analizy.

W przeciwnym razie możesz robić, co chcesz z pamięcią RAM.


4

Jak wskazano w poprzednich odpowiedziach, najpierw poleciłbym pozostawić tablicę statyczną, jeśli pasuje do pamięci. W większości przypadków znacznie ważniejsze jest, aby mieć deterministyczny ślad pamięci, nawet jeśli oznacza to, że „marnujesz” pamięć na zmienne, które nie są używane przez cały czas. Umieszczenie dużych tablic na stosie zdecydowanie zbyt łatwo go wysadzi, a przepełnienie stosu może powodować trudne do znalezienia i trudne do odtworzenia problemy (jeśli nie możesz użyć MMU do ochrony stosu).

Sugestia dzielenia bloku z niektórymi innymi danymi ze związkiem jest poprawna przez IMO, chociaż może również być źródłem trudnych do znalezienia problemów, jeśli znajdziesz w nim nieprawidłowe zmienne.

Jeśli kończy Ci się pamięć i desperacko potrzebujesz stworzyć zmienne o krótszym czasie życia, aby ją udostępnić, zanim przeniesiesz tablicę na stos, rozważę dodanie dynamicznej alokacji pamięci, nawet jeśli ma ona swoje wady. W tym przypadku może to nie być odpowiedź, ponieważ tablica brzmi dość duża w porównaniu do dostępnej pamięci.


1

Masz jeszcze jedną opcję, jeśli masz jakąś pamięć flash. Możesz obniżyć prędkość dostępu do pamięci RAM, przechowując dane w pamięci flash oraz tam odczytując i wyszukując. Będziesz musiał załadować tylko jeden rekord na raz do pamięci RAM. Będzie to nieco bardziej skomplikowane, jeśli będziesz w stanie zaktualizować rekordy. Będziesz potrzebował segmentowego mechanizmu wyrównującego zużycie. Zrobiłem to w przeszłości i załączyłem indeks, aby przyspieszyć dostęp.


1
Robiłem to również w przeszłości, ale moje pytanie dotyczyło bardziej problemów, z którymi mógłbym się zmierzyć, gdybym to położył na stosie, a nie tak naprawdę na temat alternatyw dla pamięci RAM, gdy brakuje nam tego. Dzięki za odpowiedź, mimo wszystko
Tim

1

Zwłaszcza podczas pracy z systemami osadzonymi chcesz, aby jak najwięcej potencjalnych awarii miało miejsce w czasie kompilacji i nic nigdy nie zawiedzie w czasie wykonywania (choć fajnie, jeśli moglibyśmy to osiągnąć ...).

Tworzenie dużych tablic, które mogą być potrzebne w dowolnych stanach programu przydzielonego statycznie, robi dokładnie to - Linker ostatecznie ostrzeże Cię, że „to nie pasuje do pamięci RAM”, podczas gdy przydzielenie stosu po prostu spowodowałoby awarię programu z trudnym do debugowania stosem przelewy.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.