Condividi tramite


Procedure consigliate per la gestione dell'utilizzo della RAM in applicazioni di alto livello

Anche se il sistema operativo Azure Sphere utilizza 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 buone procedure di programmazione incorporata ti aiuterà a 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 sotto il debugger determinerà un aumento dell'utilizzo della RAM, perché la RAM utilizzata dal server di debug verrà inclusa nelle statistiche di utilizzo della RAM segnalate. Per ulteriori informazioni sulle statistiche della memoria per le applicazioni in esecuzione nel dispositivo collegato, vedi Uso della memoria in applicazioni di alto livello.

Ecco alcune procedure consigliate da seguire:

  • Allocare la memoria in anticipo (idealmente staticamente) e lasciarla allocata per tutta la durata dell'applicazione quando possibile. Questo aumenta notevolmente il determinismo dell'utilizzo della RAM dell'applicazione e riduce il rischio che l'ingombro della memoria aumenti e la frammentazione nel corso della 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 tecniche di allocazione dei chunk/pool di memoria.
    • Rivedere le pagine in pila e, se possibile, mandare a malloc() capo le chiamate con le chiamate per memset() forzare il commit delle pagine. In questo modo si garantisce che, se un'allocazione causa il superamento del limite di RAM dell'applicazione, il sistema operativo la interromperà immediatamente e prevedibilmente. L'attesa di accedere alle pagine allocate comporta il rischio di un arresto anomalo ritardato della memoria, che è più difficile da riprodurre e diagnosticare.Waiting to access allocated pages will introduce the risk of a delayed out-of-memory crash, which is harder to reproduce and diagnosi.
    • Abilita il monitoraggio dell'allocazione della memoria heap in modalità di sviluppo.
  • Evita di usare Log_Debug stringhe di grandi dimensioni e rimuovi queste chiamate (ad esempio, con un #ifdef) quando non sei in modalità di sviluppo. Log_Debug causa l'allocazione di buffer temporanei, con picchi improvvisi nell'utilizzo della RAM quando vengono usati con stringhe di grandi dimensioni.
  • Usare l'API EventLoop ogni volta che è possibile per attività asincrone periodiche, ad esempio l'interazione con le periferiche, invece di creare thread. La creazione di thread fa sì che il kernel Linux allochi memoria aggiuntiva attribuita all'applicazione. Questo riduce il determinismo dell'app in quanto aumenta la probabilità che l'utilità di pianificazione del sistema operativo cambi tra più operazioni distinte che potrebbero causare il superamento del limite di RAM dell'applicazione. Molte applicazioni di esempio Azure Sphere, ad esempio il GPIO_HighLevelApp, dimostrano come usare EventLoop.
  • Evitare l'uso prematura delle cache di memoria per i valori che possono essere ricalcorati in fase di esecuzione.
  • Quando si usa libcurl:
    • Regolare le dimensioni massime del buffer del socket quando si usa libcurl. Azure Sphere OS allocherà buffer socket che vengono attribuiti all'utilizzo della RAM dell'applicazione. La riduzione di queste dimensioni del buffer può essere un buon modo per ridurre il footprint di RAM dell'applicazione. Tenere presente che l'utilizzo di 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 di CURLOPT_SOCKOPTFUNCTION libcurl.

      • I parametri di CURLOPT_BUFFERSIZE e CURLOPT_UPLOAD_BUFFERSIZE di livello superiore possono essere ottimizzati allo stesso modo.

      • Libcurl supporta anche l'override delle funzioni di memoria interna utilizzando curl_global_init_mem e passando funzioni di callback per malloc, free, realloc, strdupe calloc. 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 utilizzare questi callback per allocare la memoria libcurl da tale pool. Questa può essere una tecnica efficace per impostare guardrail e aumentare il determinismo della vostra applicazione. Per ulteriori informazioni su come usare questi callback, vedere la documentazione di curl_global_init_mem libcurl.

        Nota

        Questo meccanismo di callback non copre tutte le allocazioni di memoria causate da libcurl, solo quelle effettuate direttamente da libcurl stesso. In particolare, le allocazioni effettuate da wolfSSL sotto non sono monitorate.