Procedure consigliate per la gestione dell'utilizzo della RAM nelle applicazioni di alto livello
Importante
Questa è la documentazione di Azure Sphere (legacy). Azure Sphere (legacy) viene ritirato il 27 settembre 2027 e gli utenti devono eseguire la migrazione ad Azure Sphere (integrato) entro questo periodo. Usare il selettore di versione posizionato sopra il sommario per visualizzare la documentazione di Azure Sphere (integrata).
Anche se il sistema operativo Azure Sphere usa il kernel Linux come base, è importante ricordare che si stanno ancora scrivendo applicazioni per un dispositivo incorporato con vincoli di RAM significativi. L'applicazione di procedure di programmazione incorporate valide consente di creare applicazioni Azure Sphere affidabili.
Importante
Per ottenere informazioni accurate sull'utilizzo della RAM per l'applicazione, è importante eseguire l'app senza eseguire il debug. L'esecuzione dell'app nel debugger comporterà l'aumento dell'utilizzo della RAM, perché la RAM utilizzata dal server di debug verrà inclusa nelle statistiche di utilizzo della RAM segnalate. Per altre informazioni sulle statistiche di memoria per l'applicazione in esecuzione nel dispositivo collegato, vedere Uso della memoria nelle applicazioni di alto livello.
Ecco alcune procedure consigliate da seguire:
- Allocare la memoria in anticipo (idealmente in modo statico) e lasciarla allocata per la durata dell'applicazione quando possibile. Ciò aumenterà notevolmente il determinismo dell'utilizzo della RAM dell'applicazione e ridurrà il rischio di aumento e frammentazione del footprint della memoria per tutta la durata dell'applicazione.
- Quando l'allocazione dinamica è assolutamente necessaria:
- Provare a ridurre al minimo la frequenza delle allocazioni di memoria heap e delle deallocazione eseguite dall'applicazione per ridurre i rischi di frammentazione della memoria heap, ad esempio sfruttando le tecniche di allocazione blocchi/pool di memoria.
- Esaminare le pagine dello stack e, quando possibile, eseguire il wrapping delle chiamate a
malloc()
con chiamate a permemset()
forzare il commit delle pagine. Ciò consente di garantire che se un'allocazione causa il superamento del limite di RAM dell'applicazione, il sistema operativo lo terminerà immediatamente e prevedibilmente. L'attesa di accedere alle pagine allocate comporta il rischio di un arresto anomalo ritardato della memoria insufficiente, che è più difficile da riprodurre e diagnosticare. - Abilitare il rilevamento dell'allocazione della memoria heap in modalità di sviluppo.
- Evitare di usare
Log_Debug
con stringhe di grandi dimensioni e rimuovere queste chiamate (ad esempio, con un )#ifdef
quando non sono in modalità di sviluppo.Log_Debug
fa sì che i buffer temporanei vengano allocati, causando picchi improvvisi nell'utilizzo della RAM quando vengono usati con stringhe di grandi dimensioni. - Usare l'API EventLoop quando possibile per le attività asincrone periodiche, ad esempio l'interazione con le periferiche, anziché creare thread. La creazione di thread fa sì che il kernel Linux alloca memoria aggiuntiva assegnata all'applicazione. In questo modo si riduce il determinismo dell'app man mano che aumenta la probabilità del passaggio dell'utilità di pianificazione del sistema operativo tra più operazioni distinte che potrebbero causare il superamento del limite di RAM dell'applicazione. Molte delle applicazioni di esempio di Azure Sphere, ad esempio il GPIO_HighLevelApp, illustrano come usare EventLoop.
- Evitare l'uso prematuro delle cache di memoria per i valori che possono essere ricompilate in fase di esecuzione.
- Quando si usa libcurl:
Ottimizzare le dimensioni massime del buffer socket quando si usa libcurl. Il sistema operativo Azure Sphere allocherà i buffer socket attribuiti all'utilizzo della RAM dell'applicazione. La riduzione di queste dimensioni del buffer può essere un buon modo per ridurre il footprint della RAM dell'applicazione. Si noti che rendere i buffer del socket troppo piccoli influirà negativamente sulle prestazioni di libcurl. Ottimizzare invece le dimensioni massime del buffer per lo scenario:
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);
Vedere la documentazione CURLOPT_SOCKOPTFUNCTION libcurl.
I parametri di CURLOPT_BUFFERSIZE e CURLOPT_UPLOAD_BUFFERSIZE di livello superiore possono essere ottimizzati in modo analogo.
Libcurl supporta anche l'override delle funzioni di memoria interne usando
curl_global_init_mem
e passando funzioni di callback permalloc
,realloc
free
,strdup
, ecalloc
. Questa funzionalità consente di tenere traccia delle allocazioni dinamiche o persino di modificare il comportamento. Ad esempio, è possibile allocare un pool di memoria in anticipo, quindi usare questi callback per allocare la memoria libcurl da tale pool. Questa può essere una tecnica efficace per impostare protezioni e determinismo crescente dell'applicazione. Per altre informazioni su come usare questi callback, vedere la documentazione di libcurl curl_global_init_mem .Nota
Questo meccanismo di callback non copre tutte le allocazioni di memoria causate da libcurl, ma solo quelle effettuate direttamente da libcurl stesso. In particolare, le allocazioni effettuate da wolfSSL sotto non vengono monitorate.