Najlepsze rozwiązania dotyczące zarządzania użyciem pamięci RAM w aplikacjach wysokiego poziomu
Ważne
Jest to dokumentacja usługi Azure Sphere (starsza wersja). Usługa Azure Sphere (starsza wersja) zostanie wycofana 27 września 2027 r., a użytkownicy muszą przeprowadzić migrację do usługi Azure Sphere (zintegrowanej) do tej pory. Użyj selektora wersji znajdującego się powyżej spisu treści, aby wyświetlić dokumentację usługi Azure Sphere (zintegrowaną).
Mimo że system operacyjny Usługi Azure Sphere używa jądra systemu Linux jako podstawy, należy pamiętać, że nadal piszesz aplikacje dla urządzenia osadzonego ze znacznymi ograniczeniami pamięci RAM. Zastosowanie dobrych rozwiązań w zakresie programowania osadzonego pomoże Ci tworzyć niezawodne aplikacje usługi Azure Sphere.
Ważne
Aby uzyskać dokładne informacje o użyciu pamięci RAM dla aplikacji, ważne jest, aby uruchomić aplikację bez debugowania. Uruchomienie aplikacji w debugerze spowoduje zawyżone użycie pamięci RAM, ponieważ pamięć RAM zużywana przez serwer debugowania zostanie uwzględniona w zgłoszonych statystykach użycia pamięci RAM. Aby uzyskać więcej informacji na temat statystyk pamięci dla aplikacji uruchomionej na dołączonym urządzeniu, zobacz Użycie pamięci w aplikacjach wysokiego poziomu.
Oto kilka najlepszych rozwiązań, które należy wykonać:
- Przydziel pamięć z góry (najlepiej statycznie) i pozostaw ją przydzieloną do okresu istnienia aplikacji, gdy jest to możliwe. Znacznie zwiększy to determinizm użycia pamięci RAM aplikacji i zmniejszy ryzyko zwiększenia ilości pamięci i fragmentacji w okresie istnienia aplikacji.
- Gdy alokacja dynamiczna jest absolutnie niezbędna:
- Spróbuj zminimalizować częstotliwość alokacji pamięci sterty i przydziałów wykonywanych przez aplikację, aby zmniejszyć ryzyko fragmentacji pamięci sterty, na przykład dzięki wykorzystaniu technik alokacji fragmentów/puli pamięci.
- Przejrzyj strony stosu i, jeśli to możliwe, zawijaj wywołania za
malloc()
pomocą wywołań w celumemset()
wymuszenia zatwierdzenia stron. Pomaga to zagwarantować, że jeśli alokacja spowoduje przekroczenie limitu pamięci RAM przez aplikację, system operacyjny zostanie natychmiast zakończony i przewidywalnie. Oczekiwanie na dostęp do przydzielonych stron spowoduje ryzyko wystąpienia opóźnionego awarii poza pamięcią, co jest trudniejsze do odtworzenia i zdiagnozowania. - Włącz śledzenie alokacji pamięci sterty w trybie programowania.
- Unikaj używania
Log_Debug
z dużymi ciągami i usuwaj te wywołania (na przykład z )#ifdef
w trybie programowania.Log_Debug
powoduje przydzielanie tymczasowych, co prowadzi do nagłych wzrostów użycia pamięci RAM w przypadku użycia dużych ciągów. - Użyj interfejsu API EventLoop zawsze, gdy jest to możliwe w przypadku okresowych zadań asynchronicznych (takich jak interakcja z urządzeniami peryferyjnymi) zamiast tworzenia wątków. Tworzenie wątków powoduje przydzielenie dodatkowej pamięci przypisanej do aplikacji przez jądro systemu Linux. Zmniejsza to determinizm aplikacji, ponieważ zwiększa prawdopodobieństwo przełączania harmonogramu systemu operacyjnego między wieloma różnymi operacjami, które mogą spowodować przekroczenie limitu pamięci RAM przez aplikację. Wiele przykładowych aplikacji usługi Azure Sphere, takich jak GPIO_HighLevelApp, pokazuje, jak używać obiektu EventLoop.
- Unikaj przedwczesnego użycia pamięci podręcznych dla wartości, które można ponownie skompilować w środowisku uruchomieniowym.
- W przypadku korzystania z biblioteki libcurl:
Dostosuj maksymalne rozmiary buforu gniazda podczas korzystania z biblioteki libcurl. System operacyjny usługi Azure Sphere przydziela gniazd przypisane do użycia pamięci RAM aplikacji. Zmniejszenie tych rozmiarów może być dobrym sposobem na zmniejszenie ilości pamięci RAM aplikacji. Należy pamiętać, że zbyt małe gniazd będą miały negatywny wpływ na wydajność biblioteki libcurl. Zamiast tego dostosuj maksymalne rozmiary buforu dla danego scenariusza:
static int sockopt_callback(void* clientp, curl_socket_t curlfd, curlsocktype purpose) { int size = /*specify max buffer sizes here (in bytes)*/ int size_size = sizeof(size); setsockopt(curlfd, SOL_SOCKET, SO_SNDBUF, &size, &size_size); setsockopt(curlfd, SOL_SOCKET, SO_RCVBUF, &size, &size_size); return CURL_SOCKOPT_OK; } // Place the following along with other calls to curl_easy_setopt curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, &sockopt_callback);
Zapoznaj się z dokumentacją CURLOPT_SOCKOPTFUNCTION libcurl.
Parametry CURLOPT_BUFFERSIZE wyższego poziomu i CURLOPT_UPLOAD_BUFFERSIZE mogą być podobnie dostrojone.
Biblioteka Libcurl obsługuje również zastępowanie funkcji pamięci wewnętrznej przy użyciu funkcji
curl_global_init_mem
wywołania zwrotnego dlamalloc
funkcji ,strdup
free
realloc
, i .calloc
Ta funkcja umożliwia śledzenie dynamicznych alokacji, a nawet zmianę zachowania. Można na przykład przydzielić pulę pamięci z góry, a następnie użyć tych wywołań zwrotnych, aby przydzielić pamięć libcurl z tej puli. Może to być efektywna technika ustawiania barier zabezpieczających i zwiększania determinizmu aplikacji. Aby uzyskać więcej informacji na temat korzystania z tych wywołań zwrotnych, zobacz dokumentację curl_global_init_mem libcurl.Uwaga
Ten mechanizm wywołania zwrotnego nie obejmuje wszystkich alokacji pamięci spowodowanych przez bibliotekę libcurl, tylko te wykonane bezpośrednio przez sam libcurl. W szczególności alokacje wykonane przez wolfSSL pod spodem nie są śledzone.